Andrey Andreev <n...@devilix.net> wrote: > When I said I don't claim to fully understand LSP
Hi Andrey, The RFC specifically didn't mention LSP....because that is separate from co/contravariance. It's unfortunate for other people to be throwing the two around at you with a lack of precision. (disclaimer - I helped Niklas draft the RFC, but I still muddle up the terms occassionaly also.) > What I don't understand is how do we get from this...To this: It's not difficult, just subtle. First, some code, to define some classes: interface A { function foo(Bar $bar); } class B implements A { function foo($bar) { // this function is capable of handling either objects // of type Bar, or strings } } There are two separate things here. First - method B::foo is contravariant to method A::foo, which just means that anything that can be successfully passed as the parameter to A::foo can also be passed to B::foo. Second - because of the contravariance, and because PHP allows classes to implement interfaces, the Liskov substition principle kicks in, and we can substitute an object of type B anywhere where an object of type A is expected. e.g. If we have a function that takes A as a parameter: function doSomething(A $a) { $a->foo(new Bar()); } Both of these are guaranteed* to be work equivalently due to LSP: doSomething(new A()); doSomething(new B()); > by the above logic, that it considers "mixed" a subtype of ... everything? No, I think you've been confused by people saying LSP where they meant contravariance. Although class B can accept either an object of type Bar, or a string that doesn't meant that a string is a sub-type of Bar. Instead because B obeys the contravariance rules for the implementation of the method, an object of type B can be substituted where A is expected. Incidentally, this would be a lot nicer if we had passed the union type RFC, and so were able to write: class B implements A { function foo(Bar|string $bar) { // hurrah for static code inspection. } } Or for avoiding 'clashing' interfaces: interface C { function foo(Bar $bar); } interface D { function foo(string $bar); } class E implements C, D { function foo(Bar|string $bar) { //This method satifies the contracts for both interfaces. } } > Every (re)definition and example talks about > substituting *objects* with their subtypes It is a little unfortunate that a lot of information about type systems is presented in object-oriented languages, as the same thing applies to things that aren't objects, e.g. arrays, generators => iterable and also callback functions e.g. the callable passed to set_exception_handler() must accept at least \Exception in PHP 5.6 and \Throwable in PHP 7, but it's fine for it to accept a wider set of parameters. cheers Dan *guarantees about program behaviour with LSP are kind of...bogus. In fact it's probably better to concentrate on how it usually makes your program be easier to write, rather than relying too heavily on it for an application to actually 'behave' correctly in all scenarios. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php