2016-05-15 12:05 GMT+02:00 Rasmus Schultz <rasmus@mindplay.dk>:
> I know you're already voting on this, but I'd like to throw in a
> couple of late comments.
>
> My main problem with this RFC is the use of the interface keyword for
> something that almost by definition is not an interface.
>
> An interface is a set of methods, but an anonymous function is just
> one function, so it can't possibly implement an interface - this only
> works because of the single method constraint and some magical mapping
> of the closure as a method implementing that single-method interface.
>
> You can't, for example, add another method to one of these
> "interfaces", which is problematic - it's inconsistent with what
> interfaces actually are.
>
> In a sense, what you've really done, is you've overloaded the
> interface concept as a means of shoehorning typedefs into the
> language.
>
> Per the example in the RFC:
>
> interface IFoo {
> public function method() : int;
> }
>
> $cb = function () implements IFoo : int {
> return 42;
> };
>
> The coupling between $cb and IFoo is explicit - but the coupling
> between IFoo::method() and the closure is implied; it's something the
> interpreter, and the person reading the code, has to reason about.
>
> The one-method limitation isn't apparent from the "interface"
> declaration - that is, nothing about the interface declaration implies
> that it's not actually an interface, e.g. is not a set of methods.
>
> On the other hand, I can see the advantages of being able to treat and
> invoke the closure as if it were an object implementing an interface -
> it just seems like there's something missing. When a function
> "implements" an interface, it puts a constraint on that interface,
> preventing it from taking on another method - it imposes this
> constraint on the interface from the outside-in, which seems really
> counter intuitive to me.
>
> From the RFC:
>
> interface IFoo {
> public function method1();
> public function method2();
> }
>
> function () implements IFoo {};
>
> This is really surprising if you thought you understood what
> interfaces are: a set of methods.
>
> What suppose I write an interface that has a single method today - and
> consumers of my library begin to implement this interface using
> closures in this manner. But then tomorrow, I add another method to my
> interface? There is suddenly now direct upgrade path, no obvious way
> to fix the code - they can't simply implement that new method and move
> on, they now have to start refactoring everything from closures to
> actual classes.
>
You can just convert the function to an anonymous class. If you add methods
to an interface,
that's a BC break for a major version, since it's not compatible anymore,
everything needs
an update either way.
> In that sense, this is worse than typedefs - at least typedefs
> consistently define precisely one function and not a set.
>
> Another disconnect from interfaces, is that objects can traditionally
> implement more than one interface - but an anonymous function can only
> implement a single interface. It's another deviation from actual
> interfaces, overloading the interface" keyword - it's inconsistent
> with interfaces, which is misleading and adds unnecessary learning
> curve.
>
Literally, an interface is something you interact with. It's important for
the consumer
not the class implementing it. If you separate your concerns, you often
have just one interface.
> Another downside of this proposal, is that a single functional
> interface effectively has two names: the type-name and the
> method-name; but both names map to the same thing, the anonymous
> closure. Method-names are necessary in interfaces because they
> identify the individual methods in a set of methods. But functional
> interfaces are not a set of methods. The functional interface
> type-name already designates the type. There is no reason it should
> need to have two names.
>
> How about the following alternative syntax?
>
> callable IFoo = function () : int;
>
> $cb = function () implements IFoo {
> return 42;
> };
>
> With this syntactic sugar, functional interfaces are distinctly
> single-method interfaces - you can't add another method.
>
> You no longer need to come up with two names for one thing.
>
> You don't need to repeat the return-type when implementing it.
>
I like that syntax, but it has its own disadvantages.
> And you don't need to specify that extra method-name when invoking it:
>
As a downside, you can't implement it in a normal class anymore and just use
an instance of that class.
> if ($cb instanceof IFoo) {
> $number = $cb();
> }
>
> It also avoids the following conundrum:
>
> interface Foo {
> public function foo();
> }
>
> interface Bar {
> public function bar();
> }
>
> class Bleet implements Foo, Bar {
> // ...
> }
>
> function fluff(Bleet $bleet) {
> $bleet(); // ERROR!
> }
>
> In this example, the fluff() function thinks it's getting an anonymous
> function implementing Foo, but that's not the case. But it could be.
> You opened that door when you decided to overload interfaces - not
> only functions can implement these interfaces, classes can too.
>
That's why you call it with the method name of the interface.