Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't override multi method from role #5047

Open
Leont opened this issue Aug 27, 2022 · 5 comments
Open

Can't override multi method from role #5047

Leont opened this issue Aug 27, 2022 · 5 comments

Comments

@Leont
Copy link
Contributor

Leont commented Aug 27, 2022

Apparently it's not possible to override a multi method from a role with an only method:

raku -e 'role Foo { multi method foo(Int) { } }; class Bar does Foo { only method foo(Str) { } }'

It is however possible to override it with a proto method

raku -e 'role Foo { multi method foo(Int) { } }; class Bar does Foo { proto method foo(Str) { } }'

This doesn't make sense and is not helpful. If I can do one I should be able to do the other.

Environment

Welcome to Rakudo™ v2022.07.
Implementing the Raku® Programming Language v6.d.
Built on MoarVM version 2022.07.
@vrurg
Copy link
Member

vrurg commented Aug 27, 2022

This is totally correct behavior. A role is mixed into the class. Methods are added, roughly, as if you'd just add them at the end of the class declaration. It is not about roles being able to override anything.

@Leont
Copy link
Contributor Author

Leont commented Aug 27, 2022

Then why does this work:

raku -e 'role Foo { method foo(Int) {say "a" } }; class Bar does Foo { method foo(Int) { say "HERE" } }; Bar.foo(1)'

or this:

raku -e 'role Foo { method foo(Int) {say "a" } }; class Bar does Foo { method foo(Int) { say "HERE" } }; Bar.foo(1)'

I find this all very inconsistent.

@vrurg
Copy link
Member

vrurg commented Aug 28, 2022

No, it is consistent because in this example when method already exists on the class the one from role is ignored.

That's why I used 'roughly' in the previous comment. It was only related to the case of multi in a role. These details are rather well explained in https://docs.raku.org/syntax/role. There is no explicit coverage for multis, but it is deductible from other pieces of information. Very briefly it all winds down to two rules:

  1. Don't override on class if it has it
  2. Apply a multi as if it is added at the end

There is a case which confuses me. If the role has its own proto, the proto from class wins and all candidates are applied into it. I'd rather expect the role's "proposal" to be ignored in this case...

@jnthn
Copy link
Member

jnthn commented Aug 28, 2022

Just to make sure everyone's on the same page with the underlying structure:

  • Classes don't directly have multi methods in the method table; rather, they have a proto method in the method table
  • When a multi method is declared, it is added to a "candidates to incorporate" table
  • At class composition time, if a proto is declared already in the class then the multi candidates will be added to that. Otherwise, it looks at the base class(es) and sees if there is a proto there, cloning it if so. Failing that, it generates an only-star proto.

Now on the issue at hand.

It is however possible to override it with a proto method

This isn't overriding anything; it's just suppressing the auto-generation of a proto by explicitly providing one. The multi candidate from the role is then added to that proto during composition. Allowing the class to provide the controlling proto and then having it gather the various multi candidates from the role into it seems reasonable to me.

Apparently it's not possible to override a multi method from a role with an only method

I'd lean towards the expectations of @Leont here and suggest we change the role composer such that the presence of an only method of a given name in the class should suppress the composition of all multi methods of that name. Care must be taken that an only method from one role and a multi from another is still treated as a conflicting request, however.

@vrurg
Copy link
Member

vrurg commented Aug 28, 2022

This isn't overriding anything; it's just suppressing the auto-generation of a proto by explicitly providing one. The multi candidate from the role is then added to that proto during composition. Allowing the class to provide the controlling proto and then having it gather the various multi candidates from the role into it seems reasonable to me.

I'd still suggest that if a role defines own proto the candidates are to be put in that proto and if the class defines another one of the same name then role's proposal is dropped altogether.

For two protos from two roles the conflict resolution is to be applied.

The point is that a role developer might have different expectations while developing candidates and the expectations may not be fulfilled by class' proto resulting in unpredictable errors.

More complicated behavior may involve signature comparison.

I'd lean towards the expectations of @Leont here and suggest we change the role composer such that the presence of an only method of a given name in the class should suppress the composition of all multi methods of that name. Care must be taken that an only method from one role and a multi from another is still treated as a conflicting request, however.

Makes sense, actually. I would try to look into if when time allows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants