2014-11-25 23:42 GMT+01:00 Nikita Popov <nikita....@gmail.com>:

> On Tue, Nov 25, 2014 at 11:13 PM, Marc Bennewitz <dev@mabe.berlin> wrote:
>
> >
> > Am 25.11.2014 um 22:43 schrieb Levi Morrison:
> >
> >  On Tue, Nov 25, 2014 at 2:07 PM, Marc Bennewitz <dev@mabe.berlin>
> wrote:
> >>
> >>> 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();
> >>>      }
> >>> }
> >>>
> >> It seems that I did not explain this clearly enough; I apologize. The
> >> variance has to do with the declared type in the function signature
> >> when inheritance is involved, not the type of the value returned by
> >> the function.
> >>
> >> For instance, under any of the three options this code will work just
> >> fine:
> >>
> >> class Foo {}
> >> class Goo  extends Foo {}
> >>
> >> class FooFactory {
> >>      function create(): Foo { return new Goo(); }
> >> }
> >>
> >> As long as the return value from FooFactory::create returns Foo or a
> >> subtype of Foo (such as Goo), then it will work.
> >>
> >> The variance that is under discussion in this thread is about the
> >> declared return type in the signature:
> >>
> >> class GooFactory extends FooFactory {
> >>      function create(): Goo {}
> >> }
> >>
> >> In this case, GooFactory::create() declares a return type of Goo,
> >> which is a subtype of Foo [the return type of the inherited method
> >> FooFactory::create()]. This is a covariant return type.
> >>
> >> If we choose option 3, the only possible return type for
> >> GooFactory::create is Foo.
> >>
> >> Hopefully this clarifies the issue.
> >>
> > Yes it does - thank you for explanation - my mistake :/
> >
> > Option 3 is a no go not from OOP perspective and from consistency pov as
> > we already allow this in type-hint:
> >
> > class FooFactory {
> >     function create(Foo $foo): Foo { return $foo; }
> > }
> >
> > class GooFactory extends FooFactory {
> >     function create(Goo $goo): Goo { return $goo; }
> >
> > }
> >
>
> This is not correct. Parameter typehints in PHP are invariant, so you are
> not allowed to change them during inheritance. However LSP violations
> during inheritance of *non-abstract* methods currently uses a very low
> error level (E_STRICT), so you probably didn't notice. If you try the same
> thing with an interface method or an explicitly abstract method, you will
> receive a fatal error:
>
> interface I1 {
>     function foo(A $a);
> }
> class C1 implements I1 {
>     function foo(B $b) { ... }
> }
>
> This code snippet will result in a fatal error, because it violates type
> invariance.
>
>
Let's not compare these two:

* Parameter types are contravariant, otherwise they are not type sound.
Yet, contravariance in general is of little interest (I cannot think of any
practical example), so invariance is a good compromise.

* Return types are covariant. There are many useful examples already
mentioned in this mailing list.

http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Covariant_method_return_type



Lazare INEPOLOGLOU
Ingénieur Logiciel

Reply via email to