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
subset
s 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