The code given in this thread doesn\'t work anymore: How can I rebless an object in Perl 6?
I wrote this piece of code last year, and it worked then. Now it doesn\'t
it is supposed to work with inherited classes
It never was supposed to be that general. I designed that API and implemented it in the first place, and it was only ever intended as an implementation detail of mixins.
Until very recently, it was not part of the language specification test suite - and when it did become part of it, it already had its current, more restrictive, semantics. The constraints on it are important for performance reasons: when we know a type is not one that can be the target of a mixin operation, we can JIT-compile attribute accesses on that object into something much simpler (we paid an extra conditional move on every attribute access before the change, and now only have to pay it on mixin target types).
It's possible to modify the original program to work by using the MOP to construct the class. In fact, the following isn't quite the original program; I did a small tweak for the sake of showing how one can provide methods in the subclass as an anonymous role, so as to avoid too much MOP boilerplate.
class Person { method m() { "person" } }
constant Woman = do {
my \w = Metamodel::ClassHOW.new_type(:is_mixin, :name);
w.^add_parent(Person);
w.^add_role(role { method m() { "woman" } });
w.^compose()
}
my $tom = Person.new;
my $lisa = Woman.new;
say $tom.^name; # -> Person
say $lisa.^name; # -> Woman
say $tom.m; # person
Metamodel::Primitives.rebless($tom, Woman);
say $tom.m; # woman
While that's the most semantically direct fix to the original program, there is a shorter way: use the but operator on the Person type object to produce a mixin type and return it, and then just tweak its name to your liking:
class Person { method m() { "person" } }
constant Woman = Person but role { method m() { "woman" } }
BEGIN Woman.^set_name('Woman');
my $tom = Person.new;
my $lisa = Woman.new;
say $tom.^name; # -> Person
say $lisa.^name; # -> Woman
say $tom.m;
Metamodel::Primitives.rebless($tom, Woman);
say $tom.m;
Which is only one line extra than the original anyway.