On Thursday, January 25, 2018 4:11:02 PM CST Levi Morrison wrote:
> > IMPLEMENTATION STYLE #1:  collectionof operator
> > The style of implementation I like the most is a collectionof operator in
> > parallel to the instance_of operator.  It would be instanceof's plural
> > brother, so
> > 
> > $arg collectionof \SomeClass
> > 
> > To pass the check $arg must be of the iterable psuedotype with all its
> > values being a \SomeClass object.
> > 
> > This is all well and good, but collection integrity checks are usually
> > going to be looking to see if all the members are the same scalar.
> > 
> > $arg collectionof string
> > 
> > For language consistency we would need to allow instance_of to do the
> > same,
> > which it currently does not.
> > 
> > $arg instanceof string
> > 
> > This does create duplication with the is_* family of functions, but
> > instanceof already overlaps is_a heavily.
> 
> I see no value to this operator being applied to non-array
> traversables. 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.

I concur.  I'd actually ask what the intended goal is here.

Is this to ensure that everything coming OUT of a collection is a given type, 
or that everything put IN a collection is a given type?

Asserting that "at this point in time, everything in this collection is a 
given type" is honestly fairly useless unless it's enforced to stay that way.  
I can assert that "this array currently contains only strings", but the very 
next line could change that.  Unless we go the generics-lite route and allow 
code to declare $x = array<string> (or whatever), in which case it becomes 
"enforce on the way in", and now we never need to check it because we know 
that only strings can be put in the array.

Plus, as Levi says, asserting that all values in a non-array iterable are a 
given type requires a full scan, which is often a destructive operation.

The better solution IMO is to allow for objects that enforce type on write, 
and for *different* objects that enforce type on read, even if lazy.  That is 
(pseudo code, do not take literally):

$a = new Collection<string>;
$a[] = 5; // This will TypeError

Which we can *almost* get now, but it causes an interface mismatch error:

class Strings extends ArrayObject {
    public function offsetSet(string $k, $v) {
        parent::offsetSet($k, $v);
    }
}

But that's essentially the logic we'd want.

On the read side (which you'd want for a generator or similar), the logic 
you'd want is essentially:

class Ints extends ArrayObject {
    public function current() : int {
        return parent::current();
    }
}

Which lints fine, but when I tested it just now returns strings quite happily 
without a type error, which seems wrong to me.  (Why is it doing that, and is 
it a bug?)

In any case, in neither situation is collectionof particularly useful.  What 
is useful is a syntax-level "this collection will only allow type X to be 
added" specification and a "this iterable will always return type X" 
specification, both of which would generate a runtime TypeError or a compile-
time error if it could be detected.

--Larry Garfield

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to