Raku / problem-solving

🦋 Problem Solving, a repo for handling problems that require review, deliberation and possibly debate
Artistic License 2.0
70 stars 16 forks source link

Is a COMPOSE phaser likely for Roles? #376

Open Xliff opened 1 year ago

Xliff commented 1 year ago

This is a phaser that can be added for roles that will fire whenever said role is composed on an object either at class composition time "via class A does R" or at runtime via "my $a = A.new but R".

Having such a feature could go a long way into solving some problems. Method::Also is one module that would benefit from such.

jnthn commented 1 year ago

My recollection is that a COMPOSE phaswer was once proposed, but it was realized that this is also the time at which the role body runs, and so the functionality it would provide already exists.

alabamenhu commented 1 year ago

My recollection is that a COMPOSE phaser was once proposed, but it was realized that this is also the time at which the role body runs, and so the functionality it would provide already exists.

Indeed, the COMPOSE phaser is still documented. TIL though that the role body runs at that composition time. We should document this, I feel like I've had an instance or two where it would have been useful.

I wonder if the COMPOSE phaser may have been initially thought to provide some other access, e.g., sub COMPOSE($type) { ... }. That would be the only advantage over the body which afaict is ignorant of the type it's being composed into. But that might also be a breaking of OO principles too, so perhaps not the best idea.

jnthn commented 1 year ago

That would be the only advantage over the body which afaict is ignorant of the type it's being composed into.

The target class is in ::?CLASS:

$ raku -e 'role R { say qq[Composing into {::?CLASS.^name}] }; class C does R {}'
Composing into C
vrurg commented 1 year ago

I'm not currently ready to clearly recall what was the context, but there is actually another stage, where COMPOSE can be considered useful. I think, it was about conretization composition time. Correspondingly, the phaser was supposed to be invoked on the concretization itself.

BTW, for 6.e a submethod COMPOSE can be used for this purpose. And this is something that can be done right away. Moreover, the submethod can be utilized for this purpose for classes and parametric roles too, if considered useful. Akin to BUILD/TWEAK but at type object level.

Xliff commented 1 year ago

Here's a situation where the role body does NOT fire:

role R { 
  say qq[Composing into { ::?CLASS.^name }]; 
} 

class A does R {};  # Fires
class B {}; 
my $b = B.new but R; # Fires
my $c = B.new; 
$c does R; # Does NOT fire
lizmat commented 1 year ago

That's because the type B+{R} has been created already by my $b = B.new but R, so no new type needs to be created for $c does R, and so the role body does not get run.

If you swap them around, you'll see that it does fire on the does if it's the first one.

my $c = B.new; 
$c does R; # Fires
my $b = B.new but R; # Does NOT fire
vrurg commented 1 year ago

That's because the type B+{R} has been created already by my $b = B.new but R

Let me add to this that would there be a phaser it wouldn't fire either.

Xliff commented 1 year ago

I see. Thanks for the explanation, @lizmat

vrurg commented 1 year ago

BTW, forgot to mention here that I have an experimental solution for COMPOSE submethod in rakudo/rakudo#5312

jubilatious1 commented 11 months ago

Is COMPOSE the non-Grammar equivalent of make/made?