Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:79179 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 23566 invoked from network); 25 Nov 2014 21:07:42 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 25 Nov 2014 21:07:42 -0000 Authentication-Results: pb1.pair.com header.from=dev@mabe.berlin; sender-id=unknown Authentication-Results: pb1.pair.com smtp.mail=dev@mabe.berlin; spf=permerror; sender-id=unknown Received-SPF: error (pb1.pair.com: domain mabe.berlin from 80.237.132.167 cause and error) X-PHP-List-Original-Sender: dev@mabe.berlin X-Host-Fingerprint: 80.237.132.167 wp160.webpack.hosteurope.de Received: from [80.237.132.167] ([80.237.132.167:44758] helo=wp160.webpack.hosteurope.de) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id A0/6D-40624-B9FE4745 for ; Tue, 25 Nov 2014 16:07:40 -0500 Received: from dslb-088-074-069-014.088.074.pools.vodafone-ip.de ([88.74.69.14] helo=[192.168.178.30]); authenticated by wp160.webpack.hosteurope.de running ExIM with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) id 1XtNKi-0000J2-PF; Tue, 25 Nov 2014 22:07:36 +0100 Message-ID: <5474EF98.8070602@mabe.berlin> Date: Tue, 25 Nov 2014 22:07:36 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 MIME-Version: 1.0 To: internals@lists.php.net References: In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit X-bounce-key: webpack.hosteurope.de;dev@mabe.berlin;1416949660;a77252ad; Subject: Re: [PHP-DEV] [RFC][Discussion] Return Type Variance Checking From: dev@mabe.berlin (Marc Bennewitz) I think it's required to do the type check on runtime (Option 2) because one of the use cases for return type-hint are factories and such often do instantiation in base of unknown string values: class MyFactory { public static function factory($name) : AdapterInterface { $class = 'MyNamespace\Adapter\' . $name; return $class(); } } Marc Am 25.11.2014 um 18:08 schrieb Levi Morrison: > Dear Internals, > > As you may remember, I closed the voting on the return types > [RFC](https://wiki.php.net/rfc/returntypehinting) because of a design > flaw that was found during the voting process. The purpose of this > discussion thread is to explain the various options for checking > return type compatibility with parent methods that I think are viable, > to show some of the benefits and drawbacks of each option, and to > solicit feedback on which options you prefer and why. As such, it's > much longer than a normal message I would send. > > The following code demonstrates the design flaw mentioned above: > > class A { > function foo(): B { return new B; } > } > > class B extends A { > function foo(): C { return new C; } > } > > class C extends B {} > > $b = new B; > $c = $b->foo(); > > I've also used it because it can adequately show the differences in > how each of the following options work: > > 1. Do covariant return types; check them at definition time > 2. Do covariant return types; check them at runtime > 3. Do invariant return types; check them at definition time > > Option 1: Covariant return types with definition time checking > -------------------------------------------------------------- > This is the option that is currently implemented in my pull request. > This option catches all return type variance issues whether code is > used or not; if it got included it is checked. This means return type > variance issues can't bite you later. > > When class B is defined, the engine needs to check that the method > `B::foo` has a compatible return type with `A::foo`, in this case that > equates to checking that C is compatible with type B. This would > trigger autoloading for C but it will fail in this case because C is > defined in the same file. Note that there are ways we could fix this > issue, but not reliably because of conditionally defined classes > (defining classes in if blocks, for example) and other such dynamic > behavior. Even if we could fix this issue, there is still an issue if > A, B and C were defined in separate files and then included. You > couldn't require them in any order for it to work; you would have to > autoload. > > Option 2: Covariant return types with runtime checking > ------------------------------------------------------ > This option would do the variance check when the method is used (or > potentially when the class is instantiated, or whichever comes first). > Regardless of the exact details of how this method is implemented, the > above code would work because the first time class B is used in any > way occurs after C is defined. This would also work if you separated > them out into different files > > This option would be slower than option 1, but cannot quantify it > because it is not yet implemented. I suspect there would be a way to > cache the result of the variance check to not have to do it on every > instantiation or invocation, so this may be negligble. > > This option has the drawback that inheritance problems can exist in > the code and won't be discovered until the code is ran. Let me repeat > that to make sure that everyone understand it: if you have return type > variance errors in your code, they would not be detected until you try > to use the class or method. > > Option 3: Invariant return types with definition time checking > -------------------------------------------------------------- > This means that the declared types must *exactly match* after > resolving aliases such as parent and self. The advantage of this > option is that the inheritance check can be done at definition time in > all cases without triggering an autoload. As such it is a bit simpler > to implement and is slightly faster to do so. The obvious downside is > that it can't support covariant return types. > > --- > > Note that C++ and Java (and most modern languages) support covariant > return types, but C# supports only invariant return types. > > Which of these methods do you prefer the most, and which do you prefer > the least, and why? >