TSa Thomas.Sandlass-at-barco.com |Perl 6| wrote:

   sub incr (Any $x is rw)
       if $x.VAR.WHAT ~~ Str {...} # "-100" -> "-101"
       else {...}                  # "-100" ->  "-99"

This doesn't work because $x.VAR accesses the inner container and
that has constraint Any which effectively is 'where {True}'. So,
the natural solution to get at the constraint of the container the
caller uses to keep the argument value is capturing it:


if you call
 $q = "aaa";

then the value passed in is a Str. The static type is Any, the dynamic type is Str. $x.VAR.WHAT will be the prototype object for Scalar, which has nothing to do with the value inside it. $x.WHAT is the Str prototype, the same thing Str as an argument listop returns. So
    if $x.WHAT ~~ Str
will be True.

  sub incr (Any ::Type $x is rw)
       if Type ~~ Str {...} # "-100" -> "-101"
       else {...}           # "-100" ->  "-99"

Same thing, only trusting smartmatch to compare a protoobject with a metaobject.

BTW, calling incr with an rvalue can be handled as well

  sub incr (Any ::Type $x is rw)
      my $ret;
      if Type ~~ Str {...; $ret = ...}
      else {...; $ret = ...}

      ::T $x = $ret if T ~~ Type; # don't violate caller's constraint

      return $ret;

T is undefined.

  say incr(5); # print 6, no error
Compile-time error; can't bind 5 to an rw.

  my int8 $i = 5;

  incr($i); say $i; # prints 6

  $i = 127; incr($i); say $i; # prints 127, no error

I wonder if the constraint check can be written as I did. A version
with explicit WHAT is defined to have a bad smell, though. I believe
capturing the caller's container type is implicitly done by the
compiler to check constraint violation of rw parameters.

Why not just let MMD do it? Switching on the type is bad smell. Polymorphism should do that.

multi sub incr (Str $x is rw --> Str) { ... } # do the string version.
   multi sub incr (Numeric ::T $x is rw --> T)
    $x += 1;
    return $x;
I'm postulating the existence of a Numeric role that will constrain T to Int, Num, Rat, etc. and ignoring any progressive details concerning F-bounds.

   multi sub incr (Enum ::T $x is rw --> T) { ... }

Again, should match anything that is created as an enumeration, ignoring progressive details about bases that are not supertypes because of variance violations in the derived class. But assume there will be a way to say "any kind of Enum" with higher-order matching. But I'm getting ahead of myself. The body can be written without explicit testing against types, just using the generics to get to the real enumeration type with its interrogation methods.

Here's one riddle for the linguists. We have '::Any ::= where {True}'
as the constraint that permits any value. Would then '::All ::= where {False}' work as expected? That is does it intuitively mean that it forbids all values?
I've not plumbed the depths, but I naivly expect that the constraint is evaluated when assignment is made. If it returns False, the assignment fails. You always return False, so no value will ever be assigned without error, or no value will ever match if used in MMD.

However I've no clever idea how to denote a contra-variant constraint
on the caller's container's constraint in an rw sub. Perhaps

   sub foo (FooOut <-- FooIn $x is rw) {...}

The arrow is of course optional. Its absence means that the caller has
to provide an unconstraint container to be type save. The visual problem
with this arrow is that is cousin --> is not per parameter but for the
whole sub. Alternatively it could be a signature on the trait.

I think I see what you're getting at. But I don't see what it has to do with the container. The value bound to $x needs to be at least as general as FooIn. Hmm, or are you thinking of subset constrained containers trying to bind to $x? Currently, there is no mechanism to propagate the constraint in. If the binding chooses to work by "copy/return" mechanism, then it will be checked when the value is copied back to the original container, using that container's SET, assuming copy/return is designed and intended to reference the original container not just the differently-typed value. I can see the need for that, such as with tied variables in general. Or maybe the container for $x aliases the original container -- that might be what "is ref" is supposed to mean.

Reply via email to