On 26 January 2018 at 01:06, Michael Morris <tendo...@gmail.com> wrote:
> > On Thu, Jan 25, 2018 at 4:11 PM, Levi Morrison <le...@php.net> wrote: > > > > Our iterators cannot always be reliably rewound, such as > > when using generators. Checking that the generator returns only > > strings would consume all the input and would therefore be useless. > > > True - I hadn't thought of those. But as of PHP 7 generators can type > declare their return value. So, given `$a instanceof iterable<string>`, if > $a is a reference to a generator, then the engine could check the return > type declaration and only give true on a match without attempting to use > the generator. > > We can follow this pattern farther - The return of an > ArrayAccess::offsetGet and Iterator::current() can be similarly tested by > instanceof rather than actually pulling data from these methods. > > We are having the return rely on the promise of the code, but in each case > TypeError would be raised anyway if it breaks it's promise to instanceof so > errors aren't being avoided. > The more angles we approach this, the more it looks like generics, or at least the same basis. For instance, what you're describing here is that Iterator<string> would act like an extra interface that restricted the return type of current() to string. With full userland generics, that would actually be declarable like this: interface Iterator<T> extends Iterator { public function current(): T; public function next(): T; } Which would basically be a template so that Iterator<string> created an appropriately constrained interface, which you can actually create already: interface Iterator__string extends Iterator { public function current(): string; public function next(): string; } (You could actually use an auto-loader hack to do a lot of generics this way.) The main differences I can see between this and your suggestion are: - If it's an actual interface, the class's definition would need to explicitly list that it implements it. The wording you used implied that it might be more implicit, and automatically label the class as an "iterable<string>" if the signatures matched. - The iterable<string> syntax would be able to cover arrays as well as Iterators. We might decide that just as "iterable" stands for "Iterator or array", "iterable<string>" stands for "Iterator<string> or string[]". However, I think having "string[]" was previously rejected because of the cost of checking every element of the array, particular when the type is something slower to check, like "callable[]". I think this fits with where Derick was going earlier: we could have pseudo-generic interfaces like Iterator<string> internally without a full generics implementation. As long as the syntax and semantics were compatible, these could then be a stepping-stone to full generics being added later. Regards, -- Rowan Collins [IMSoP]