I've followed the directions from the answers to the SO question How can classes be made parametric in Perl 6?. However, I've hit some soft roadblock; I'm trying to type an internal class's attribute using the type capture and getting the following error:
Died with X::TypeCheck::Assignment
in submethod BUILDALL at ...
in method insert at ...
in block <unit> at ...
In the following example, I've typed the class BinaryNode
's $.item
attribute (with T
) but doing so causes the above error:
class BinarySearchTree {
my role BTSImpl[::T] {
my class BinaryNode is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode.new(item => $x)
}
}
method ^parameterize(Mu:U \this, Mu \T) {
my $type := this.^mixin: BTSImpl[T];
$type.^set_name: this.^name ~ '[' ~ T.^name ~ ']';
$type
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
First off, there's almost no need to perform the class
+ ^parameterize
+ role
trick. It appears in some of the internals because it helps deal with some bootstrapping problems (the kind of fun one has when defining a language in terms of itself). However, in normal Raku code, just write a parametric role
instead of a class
. From the point of view of the consumer, there's usually no difference; one can:
.new
on it to make an instance (which actually creates a class, known as a "pun", behind the scenes and makes the instance of that)new
isn't specialWith the added bonus that somebody can also compose it instead of inheriting.
Secondly, there's no relationship between a class
defined inside of a role
and the enclosing role
(this is a general principle: nesting of one package inside of another doesn't imply any relationship between them at an object model level). Thus we need to make that separately generic and instantiate it.
These two get us to:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[T].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
Which really should work, but the compiler seems to get the timing wrong on the BinaryNode[T]
. We can work around that by just forcing it to delay the paramerterization until runtime; there's many ways we may do that, but writing BinaryNode[$(T)]
compact and cheap (optimizes into pretty much no extra cost). Thus giving a working solution:
role BinarySearchTree[::T] {
my role BinaryNode[::T] is rw {
has T $.item;
has BinaryNode $.left;
has BinaryNode $.right;
}
method create-node( T $x ) {
BinaryNode[$(T)].new(item => $x)
}
}
my $bst = BinarySearchTree[Int].new;
$bst.create-node(6);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With