On 4/15/16 12:28 PM, Christoph Becker wrote:
On 15.04.2016 at 17:42, Larry Garfield wrote:

I think there's 2 general use cases for union types that would be "good
things", which are different for & and |, and have very little...
intersection.  (*yaaaaaaa!*)

The OR case is for cases where the language doesn't support a unified
case at all.  The most obvious example here is array|Traversable.  If I
want "a thing I can foreach()", then PHP right now has no way of saying
that syntactically.  You have to type on array, or Traversable, or not
type at all.  array|Traversable is what you really want,
It is not what I would want, though.

because those
DO have an overlap (foreach-ablility), PHP is just incapable of
representing that otherwise.
Maybe we should consider to accept an array as Traversable?  Actually, I
wonder why that's not already the case.

It's been asked a few dozen times, but never went anywhere. Mainly, I think, Traversable implies object, which implies certain passing semantics. Array is a primitive, so has different passing semantics. There's probably other subtle issues like that which have kept the engine-gurus from trying to make it work.

My assumption here is "if it were that easy someone would have done it already". (Which may not be an entirely accurate assumption, but seems logical given how often it's been asked for.)

A similar example would be callable|SomeInterface.  An interface can
specify a signature for __invoke(), which gives you documentation on the
format that is expected for a callable.  However, you can't strictly
enforce that because then you don't allow for a function or closure that
fits the same method signature.  That means you have to leave it
untyped.  This, I argue, would be better *and* reasonably type safe:

interface MiddlewareInterface {
   function __invoke(RequestInterface $req, ResponseInterface $res);
}

function middleware_builder(callable|MiddlewareInterface $m) {
   // ...
}

As that self-documents that MiddlewareInterface is the callable
signature we need, but still allows an arbitrary callable to be passed.
It's not perfect (I could pass a string of a function name that doesn't
have that interface and it would still explode), but it is an
improvement over middleware_builder() having no type specification at
all, as is the case today.
In my opinion, `callable' is to weak a type hint to be really useful,
and it would be better if we would improve that (generics come to mind).
  Then you wouldn't need MiddlewareInterface at all and be not afraid
that somebody passes in an incompatible function.

One of the key language design points I think we should be keeping in mind is that, on the whole, single-purpose features are inferior to more general capabilities that implicitly grant the same capability. Thus, I'd argue that the Property Accessor RFC is superior to adding a half dozen keywords to object properties (because they implicitly grant all of those same capabilities with less mental overhead and fewer keywords) and Union Types are superior to special casing array|Traversable or array|ArrayAccess, etc. (Making array a for-reals honest to goodness object would be good too, but that's a considerably larger issue.) Union Types side-step the need for more special cases, as they can be handled in user-space code. It's not a perfect fix, but the perfect fix involves very BC-unfriendly changes to PHP (making everything an object, Go-style type aliases, etc.) that are not likely to happen any time soon.

Related: What would union types mean for the typed property RFC? Would this be a good solution or an evil solution:

class Foo {
  public array|Traversable $arr;
  public Foo&Bar $c;
}

--
--Larry Garfield


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to