Skip to content

Better Role Creation #6

@wayland

Description

@wayland

Hi!

I have a class, and I want it to do two different roles, Hash::Agnostic and one of mine. Both roles have a "new" method. I have to manually resolve the conflict. I don't object to having to resolve the conflict, but I object to the idea that the .new() method role gets run in only one of those. I think there should be a better way of constructing roles so that the code in both new methods can be run. This is why I think we need an optional, more complex constructor.

Here's my idea:

method new(*@_, *%_) {
    (@_, %_) = self.WALK('BUILDARGS', :roles).invoke(|@_, |%_);
    my(@rvs, %rvs) = callwith(|@_, |%_);
    self.WALK('DECORATE', :roles).invoke(|@_, |%_);

    return(|@rvs, |%rvs);
}

This will mean that any role that does this .new() method will be able to add two extra submethods:

  • BUILDARGS: This gives the class a chance to modify the arguments before they're passed to the parent .new(). I'm not at all sure that the return values there will work the way I expect, but that's a detail that can be sorted out
  • DECORATE: This gives the class a chance to do whatever initialisation it likes, but only after the parent .new() method has completed.

Note that, unlike BUILD and TWEAK, these happen for roles as well as classes.

In the case of Hash::Agnostic, I think this would mean that:

  • We could either use the .new method above, or we could do a role that does it. Or we could make a new trait for roles that does it.
  • We would do away with the current .new() method, and end up with a DECORATE submethod that would contain: $self.STORE(@values, :initialize) if @values;

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions