Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:92662 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 29801 invoked from network); 23 Apr 2016 17:44:31 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 23 Apr 2016 17:44:31 -0000 Authentication-Results: pb1.pair.com smtp.mail=jesseschalken@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=jesseschalken@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.223.178 as permitted sender) X-PHP-List-Original-Sender: jesseschalken@gmail.com X-Host-Fingerprint: 209.85.223.178 mail-io0-f178.google.com Received: from [209.85.223.178] ([209.85.223.178:36152] helo=mail-io0-f178.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id EE/53-07837-E74BB175 for ; Sat, 23 Apr 2016 13:44:30 -0400 Received: by mail-io0-f178.google.com with SMTP id u185so148387783iod.3 for ; Sat, 23 Apr 2016 10:44:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date:message-id:subject :from:to:cc; bh=t61J9/a1x3EWn8OmFX+B5aXvjSssiGfLJkbNXgZ3A3A=; b=Vk6Xla6Bz/BXE1P+Xjk4ZGiGVAlCPfoHQ2ZgxgKNcd8CW3OOlMSrFPn1sP5AJZmaMk Oy+RHXL2yy+LfXekP2bzw0LApNoDQgi61MGrpmnp3Qdffj2cNV/AIf7WEUJSQUVV1fKq Q+d5WmcCYB5R1SvnC2kCBD+tD+8T41Muir6+g94HTFXKzStM9xd12lg8HFO4iAWtB8mI ai7iuT4X0/VYl+W10Xgs25/+j5DdYws4qZ84L2MJJqJVQfJtfjI1mMxK7EZi5PllYDu1 LokM0ePoAFdXVnAYYC9Q7bHUMtwM3zxJ44Y4eVVYvseToYKVkxkomhnoCbWjT6BuLLqC QkOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:sender:in-reply-to:references:date :message-id:subject:from:to:cc; bh=t61J9/a1x3EWn8OmFX+B5aXvjSssiGfLJkbNXgZ3A3A=; b=JhLhEdNlTsnxCx2nOi/mQDONAp3QvT0+0ZiSZ78ETLCSRhjB3oC9FN3VYCKlTBKQSl D1vWH5AuNVyx5PVGZlMMYmn8z9RqxhlrxSF0yQIHJUmy3pz7eRiQih9hObUIKt1Ir1Gx EXGm5oueibc2qvPkpS8La7rnunx3zPtpQsiQDjrOFxrBwHN4ezt3dHzqfZIJrmE0klQB y2/SZQ1SssnZRR1UglBLlfn5+vtZ/eBiQwYtORafg+HzZ/iD4iR8A7Uc8uXxCebBfIbe iVuo8SR1bfZpxD027FbvCdW/3Zxexn4X5D+HfrUPhgSYRPXrCK6ouqtFVU+qNvOkjPOc b7eg== X-Gm-Message-State: AOPr4FVV1U3HHmHIYMZZx6+2ypry+th5iAaitgTHx9LwV/xkLJ+YY3UCb4D8U+whJupu71ecX4w4WrmPP2hMLw== MIME-Version: 1.0 X-Received: by 10.107.9.102 with SMTP id j99mr26261267ioi.104.1461433467747; Sat, 23 Apr 2016 10:44:27 -0700 (PDT) Sender: jesseschalken@gmail.com Received: by 10.79.139.133 with HTTP; Sat, 23 Apr 2016 10:44:27 -0700 (PDT) In-Reply-To: References: Date: Sun, 24 Apr 2016 03:44:27 +1000 X-Google-Sender-Auth: KoUSrq4L2yy7ZbA_EZ2GnT_0inc Message-ID: To: Nikita Nefedov Cc: PHP internals Content-Type: multipart/alternative; boundary=001a113f8a5cb566ab05312a7e31 Subject: Re: [PHP-DEV][RFC] Callable Types From: me@jesseschalken.com (Jesse Schalken) --001a113f8a5cb566ab05312a7e31 Content-Type: text/plain; charset=UTF-8 I see. So it's the combination of not erroring when more parameters are passed than a function accepts, and permitting methods to add extra optional parameters that is wrong. So without the former being fix/deprecated, the correct thing to do is to disallow extra optional params. Makes sense. Are there any valid use cases for passing extra parameters to a function any more, now that there is the varargs syntax to replace func_get_args()? If not, maybe it could be deprecated by this RFC. Regarding references, by-ref invariance for parameters makes sense, and is what method compatibility does. According to method compatibility and call-time behaviour however, return by-ref is effectively a subtype of return by-value: function &returns_ref() { $f = 0; return $f; } function returns_val() { return 1; } $v1 = returns_ref(); // ok $v2 =& returns_ref(); // ok $v3 = returns_val(); // ok $v4 =& returns_val(); // Notice: Only variables should be assigned by reference interface Methods { function &returnsRef(); function returnsVal(); } class ReturnRef implements Methods { function &returnsRef() {} // ok function &returnsVal() {} // ok } class ReturnVal implements Methods { function returnsRef() {} // Fatal error: Declaration of ReturnVal::returnsRef() must be compatible with & Methods::returnsRef() function returnsVal() {} // ok } Otherwise it LGTM cheers On Sat, Apr 23, 2016 at 8:37 PM, Nikita Nefedov wrote: > On Sat, 23 Apr 2016 10:46:38 +0300, Jesse Schalken > wrote: > > This is great. The gaps in PHP's type annotations are slowly being filled. >> :) >> >> Are the rules for compatibility between callables the same rules for >> compatibility between methods in classes/interfaces? Because presently, >> this is allowed: >> >> interface Test { >> public function testMethod(); >> } >> >> function foo1(Test $x) { } >> >> foo1(new class implements Test { >> public function testMethod(int $extraParam = 0) { } >> }); >> >> >> but, according to the RFC, this would not be: >> >> function foo2(callable():void $x) { } >> >> foo2(function (int $extraParam = 0) { }); >> >> >> I don't see why they should be different. >> >> I also didn't see anything mentioning reference parameters/returns. I >> assume it just follows the rules for method compatibility? >> > > Hey Jesse, > > Thanks for reading the RFC. > > First and foremost - no, the rules for compatibility between callables > and method implementations are different at least because our > inheritance model currently doesn't support variance for every case: > > if you have > > class B extends A {} > > interface Foo { > function foo(B $b); > } > > then implementation of `foo()` can never have `foo(A $a)` signature, > which is crucial for callables for some cases. Note that callables > have runtime variance, where classes would have compile-time variance). > > So, in this way, callables have it right (it is desirable for classes > to have variance as well, but currently it's not possible as there is > a need for another compilation phase for verifying variance). > > What about your case of variance with extra optional parameter, it is > actually not type safe with the current way of how PHP works (it's > covered in the end of "Variance and Signature Validation" part). > The problem lies in the notion that passing extra arguments to the > function (the ones it doesn't even expect nor use) is considered > valid and doesn't throw an error. > So if you have a function that accepts optional argument of type B and > you pass this function as a parameter of type `callable() $cb`, then > it would be perfectly valid to call it as `$cb(new A);` because you > assume that $cb is of type `callable()` and that means if you pass > anything extra - it shouldn't Fatal. But in this case it would. > > While I agree that your use case is legit and ideally should be > supported, I don't think it is safe to support it until PHP deprecates > passing extra args to functions that don't expect them (which is very > troublesome to implement due to BC). > > Anyway, changing this behavior of callable type later on wouldn't > break BC so the gates will still be open. > > I've just added a part about references to the RFC (and found a > bug in the implementation, thanks for that =)), I'll just copy > and paste it here: > > Reference parameters are supported: no variance is applied to > the fact whether parameter is referential or not. > > Example: > > function foo(callable(&$byref) $cb) { } > > foo(function (&$bar) { }); // valid > foo(function ($bar) { }); // TypeError: Argument 1 passed to foo() > must be callable of compliant signature: callable(&$byref), callable($bar) > given > > function bar(callable($byval) $cb) { } > > bar(function (&$bar) { }); // TypeError: Argument 1 passed to bar() > must be callable of compliant signature: callable($byval), callable(&$bar) > given > > Functions returning a reference are not different from functions returning > a value in PHP, for the caller, hence both are interchangeable: > > function foo(callable(): A $cb) { } > > foo(function (): A { return new A; }); > foo(function &(): A { static $a; $a = $a ?: new A; return $a; }); // > both would pass the boundaries of a type check > > (the last one has error in the current implementation, I'll fix it later) > --001a113f8a5cb566ab05312a7e31--