(This is a follow up to: Raku rebless doesn't work with inherited classes anymore)
I have tried to come up with a more complex use case, but am unable to get the code to work.
The idea is a Person class, with mixin subclasses for Child and Adult. We have a Child object, and change the type to Adult when the age passes 18 year.
This one obviously fails, as Adult is a mixin on Parent, and not on Child:
class Person
{
has Int $.age is rw = 0;
method happy-birthday
{
$.age++;
# Metamodel::Primitives.rebless($, Adult) if $.age == 18;
}
method can-vote
{
...;
}
}
constant Adult = Person but role { method can-vote { True } }
constant Child = Person but role
{
method can-vote { False }
method happy-birthday
{
$.age++;
Metamodel::Primitives.rebless(self, Adult) if $.age == 18;
}
}
BEGIN Child.^set_name('Child');
BEGIN Adult.^set_name('Adult');
my $tom = Child.new;
say "Age Can-Vote Class";
for ^20
{
say "{ $tom.age.fmt('%3d') } { $tom.can-vote } { $tom.^name }";
$tom.happy-birthday;
}
But it runs partially:
Age Can-Vote Class
0 False Child
1 False Child
2 False Child
3 False Child
4 False Child
5 False Child
6 False Child
7 False Child
8 False Child
9 False Child
10 False Child
11 False Child
12 False Child
13 False Child
14 False Child
15 False Child
16 False Child
17 False Child
Incompatible MROs in P6opaque rebless for types Child and Adult
in method happy-birthday at ./vote-error line 28
Setting it up with just one class and one mixin is the thing:
class Child
{
has Int $.age is rw = 0;
method happy-birthday
{
$.age++;
Metamodel::Primitives.rebless($, Adult) if $.age == 18;
}
method can-vote
{
False;
}
}
constant Adult = Child but role { method can-vote { True } }
BEGIN Adult.^set_name('Adult');
my $tom = Child.new;
say "Age Can-Vote Class";
for ^20
{
say "{ $tom.age.fmt('%3d') } { $tom.can-vote } { $tom.^name }";
$tom.happy-birthday;
}
Except that it doesn't work:
Error while compiling vote-error1
Illegally post-declared type:
Adult used at line 10
I get that. The rebless line refers to Adult, which hasn't been declared yet. So I tried stubbing the class:
class Child { ... }
constant Adult = Child but role { method can-vote { True } }
class Child
{
has Int $.age is rw = 0;
method happy-birthday
{
$.age++;
Metamodel::Primitives.rebless($, Adult) if $.age == 18;
}
method can-vote
{
False;
}
}
BEGIN Adult.^set_name('Adult');
my $tom = Child.new;
say "Age Can-Vote Class";
for ^20
{
say "{ $tom.age.fmt('%3d') } { $tom.can-vote } { $tom.^name }";
$tom.happy-birthday;
}
But stubbing and inheritance doesn't like each other:
===SORRY!=== Error while compiling vote-error2
'Child+{<anon|1>}' cannot inherit from 'Child' because 'Child' isn't composed yet (maybe it is stubbed)
Then I tried adding a new mixin to avoid the circular reference problem:
class Child
{
has Int $.age is rw = 0;
method can-vote
{
False;
}
}
constant Adult = Child but role { method can-vote { True } }
BEGIN Adult.^set_name('Adult');
role still-a-child
{
method happy-birthday
{
$.age++;
Metamodel::Primitives.rebless($, Adult) if $.age == 18;
}
}
my $tom = Child.new but still-a-child;
say "Age Can-Vote Class";
for ^20
{
say "{ $tom.age.fmt('%3d') } { $tom.can-vote } { $tom.^name }";
$tom.happy-birthday;
}
But that failed as well:
Age Can-Vote Class
0 False Child+{still-a-child}
1 False Child+{still-a-child}
2 False Child+{still-a-child}
3 False Child+{still-a-child}
4 False Child+{still-a-child}
5 False Child+{still-a-child}
6 False Child+{still-a-child}
7 False Child+{still-a-child}
8 False Child+{still-a-child}
9 False Child+{still-a-child}
10 False Child+{still-a-child}
11 False Child+{still-a-child}
12 False Child+{still-a-child}
13 False Child+{still-a-child}
14 False Child+{still-a-child}
15 False Child+{still-a-child}
16 False Child+{still-a-child}
17 False Child+{still-a-child}
Cannot change the type of a Any type object
in method happy-birthday at vote-error3 line 26
And it did as $tom is now something else than a Child, and Adult isn't a mixin of what we now have. But the error message isn't very helpful.
The last one is essentially the same as the first one.
And I am stuck.