Parametrized types in Raku, how to use run time values as parameters

Actually, unlike I said in my previous you can use conditions in where clauses without problem, you just need to encase them in braces:

role Zipi[$condition] {
    has $.floor is rw where {$_ ~~ $condition}
    method foo($x) { $!floor = $x }
}

class A does Zipi[2 < * < 5] {
    method bar($x) { $.floor = $x }
}

#my $a = A.new( floor => 10); # error
my $a = A.new( floor => 4); # OK

#$a.foo(10); # error
$a.foo(3); # OK

#$a.bar(0); # error
$a.bar(4); # OK

#$a.floor = 9; # error
$a.floor = 3; # OK

That should cover all of the assignment types


I tried using anonymous where clauses, but similarly to no avail, but I tracked down the issue: the where clause is apparently being ignored by the BUILD method . I'm not sure if it's because it has direct access (via $!floor) which bypasses the where clause, or if something else weird is going on (probably the latter, I general got Nil if I tried to use the paramaterized value in a where clause).

Nonetheless, this should work nicely, including giving a helpful error message:

role Zipi[$condition] {
    has $.floor;

    submethod BUILD(:$floor, |c) {
        die "Invalid floor number."
            unless $floor ~~ $condition;
        $!floor = $floor;
    }
}

You can see how it'd be easy to modify if you can assume floors are always 0 .. x, or x .. y and could provide an even more helpful error message.


A nanswer covering the case a reader knows Java but not Raku.

Collection<String> coll = new LinkedList<String>();

parametrized types for Raku

The linked Java example is:

The instantiation of a generic type with actual type arguments is called a parameterized type. Example (of a parameterized type):

Collection<String> coll = new LinkedList<String>();

A reasonable Raku analog is:

my Positional[Str] \coll = Array[Str].new;

The Positional type is a parameterizable role. A role specifies an interface and/or partial implementation of a type. I believe Raku's Positional is sufficiently analogous to Java's Collection that it serves for the purposes of this nanswer.

The Array type is a parameterizable class. It specifies a data structure that adheres to the Positional role. It isn't a linked list but it will suffice for the purposes of this nanswer.


I have very limited MOP chops, and the following seems ugly, but it works, and might be a step in the right direction.

What I've done:

  • Dynamically constructed an array of 10,000 subsets via the MOP.

  • Time shifted their construction to compile time via BEGIN.

  • Used an appropriate element from the array to parameterize the role.

my @max-floors-checkers; 
BEGIN {
  @max-floors-checkers = do for ^10_000 -> \floors {
    Metamodel::SubsetHOW.new_type: 
      refinee => UInt,
      refinement => { $^floors <= floors }
    }
}

role BuildingCategory[ ::MaxFloorsCheck ] { has MaxFloorsCheck $.floors }
    
class Capped-at-three does BuildingCategory[ @max-floors-checkers[3] ] {}

my $capped3 = Capped-at-three.new( floors => 2 );
say $capped3.raku;                                # Capped-at-three.new(floors => 2

my $capped4 = Capped-at-three.new( floors => 4 ); # Type check failed 

Tags:

Raku

Roles