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

Use of submethods in roles causes compiler to freeze #2250

Open
vrurg opened this issue Sep 6, 2018 · 2 comments

Comments

Projects
None yet
3 participants
@vrurg
Copy link
Member

commented Sep 6, 2018

The Problem

When two roles define submethods with the same name if one consuming another and then been itself consumed by a class then compiler cannot deal with this and freezes without any message to the user.

Expected Behavior

Compilation must pass unless there is a rule restricting use of submethods in roles.

Steps to Reproduce

This code:

     role FooRole {
         submethod a {
             "this is FooRole::a";
         }
     }

     role BarRole does FooRole {
         submethod a {
             note "this is BarRole::a";
         }
     }

     class Foo does BarRole {
         submethod a {
             "class::a";
         }
     }

effectively demonstrates the bug.

Environment

  • Operating system: macOS 10.13, Linux 4.15.0-33-generic #36-Ubuntu SMP
  • Compiler version (perl6 -v): This is Rakudo version 2018.06 built on MoarVM version 2018.06
    Tested with 2018.08 and 2017.10 too with same results.

@vrurg vrurg changed the title Use of submethods in roles might cause compiler to freeze Use of submethods in roles causes compiler to freeze Sep 6, 2018

@b2gills

This comment has been minimized.

Copy link
Contributor

commented Feb 8, 2019

Part of the point of submethod is that it doesn't participate in the method resolution the same way as methods.

class A {
  submethod foo () { say 'A::foo' }

  method call-all-foo (){
    for self.^mro -> ::Type {
        if Type.can('foo') -> $_ {
            .head.(self)
        }
    }
}
class B is A {
}
class C is B {
  submethod foo () { say 'C::foo' }
}

C.call-all-foo();
# C::foo
# A::foo

B.foo();
# No such method 'foo' for invocant of type 'B'. …

I think it makes sense for that to be extended so that a submethod in a role doesn't get composed in, but can still be called.

That is I think it should work this way:

role R {
  submethod foo () { say 'R::foo' }
}
class C does R {
}

C.foo();
# No such method 'foo' for invocant of type 'C'. …
# (currently this calls the `foo` in R)

C.R::foo();
# R::foo
# (currently this is an error)

I think that doing this will fix many issues around submethod being used in a role.

(Note that there needs to be tests that BUILD / TWEAK and DESTROY in a role get's called if this change happens.)

@vrurg

This comment has been minimized.

Copy link
Member Author

commented Feb 8, 2019

@b2gills Thanks Brad! I think that your comment rather belongs to #2677.

This is my point of view too. submethod must solely belong to where it was declared. Period. To make iteration over submethods easier .^mro would require a named parameter to indicate willingness of the caller to accept both classes and roles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.