Failover for binding to a Positional
role PositionalBindFailover { ... }
This role provides an interface by which an object can be coerced into a Positional when binding to Positional parameters.
For example, Seq type is not Positional, but you can still write the following, because it does PositionalBindFailover role:
sub fifths(@a) { # @a is constraint to Positional
@a[4];
}
my $seq := gather { # a Seq, which is not Positional
take $_ for 1..*;
}
say fifths($seq); # OUTPUT: «5»
The invocation of fifths in the example above would ordinarily give a type error, because $seq is of type Seq, which doesn't do the Positional interface that the @-sigil implies.
But the signature binder recognizes that Seq does the PositionalBindFailover role, and calls its cache method to coerce it to a List, which does the Positional role.
The same happens with custom classes that do the role; they simply need to provide an iterator method that produces an Iterator:
class Foo does PositionalBindFailover {
method iterator {
class :: does Iterator {
method pull-one {
return 42 unless $++;
IterationEnd
}
}.new
}
}
sub first-five (@a) { @a[^5].say }
first-five Foo.new; # OUTPUT: # OUTPUT: «(42 Nil Nil Nil Nil)»
method cache(PositionalBindFailover:D: --> List:D)
Returns a List based on the iterator method, and caches it. Subsequent calls to cache always return the same List object.
multi method list(::?CLASS:D:)
Returns a List based on the iterator method without caching it.
method iterator(PositionalBindFailover:D:) { ... }
This method stub ensure that a class implementing role PositionalBindFailover provides an iterator method.