problem-solving icon indicating copy to clipboard operation
problem-solving copied to clipboard

Should the `handles` trait delegate by name or by code reference?

Open vrurg opened this issue 3 years ago • 1 comments

When handles delegates via a method call there are two approaches:

  • the original one we used for years was by delegating via method name: `self."$meth_name"()."$delegation_name"()
  • the one I introduced with my fix for roles uses &method_code_object(self)."$delegation_name"()

There are a number of problems about the former approach. First, it makes it possible for a child to override the handling method and break the delegation by returning an object of different type:

class C1 {
    method dt handles<year month day> { DateTime.now }
}
class C2 is C1 {
    method dt { "something different" }
}
say C2.new.year; # 2022 on the master, dies on 2022.06

Second, the new approach allows for anonymous methods to do delegation too:

class Foo { }
Foo.^add_method("dt", anon method () handles<year> { DateTime.now });
say Foo.year; # Dies on 2022.06

Third, multi-dependent delegation works the way it is expected to:

class C {
    multi method foo(::?CLASS:U:) handles<year> { DateTime.now }
    multi method foo(::?CLASS:D:) handles<Int> { "42" }
}
# Weird "No such method 'Int' for invocant of type 'DateTime'" on 2022.06,
# and more correct "Invocant of method 'foo' must be an object instance of type 'C', not a type object of type 'C'. 
# Did you forget a '.new'?" on the master
say C.Int;

Both approaches pass specs.

The only problem is the code object approach breaks CSS and LibXML due to some of their child classes overriding a method with an attribute of the same name.

Related is rakudo/rakudo#5006

vrurg avatar Jul 28 '22 00:07 vrurg

I tried to make the code object behavior 6.e feature, while preserving the name-based one in 6.c/d. Seems to be working nicely, but it is too late today to release it.

vrurg avatar Jul 28 '22 03:07 vrurg