How do you add a method to an existing class in Perl 6?

后端 未结 4 1872
太阳男子
太阳男子 2021-02-19 04:40

The Int class has a method is_prime, so I figured, just for giggles, I\'d like to add some other methods to Int for some of my hobby projects that do n

相关标签:
4条回答
  • 2021-02-19 05:26

    There's another interesting way to do this if you need it only for some instances of a class. You can decorate an object with a role:

     my $decorated = $object but role { ... }
    
    0 讨论(0)
  • 2021-02-19 05:29

    You can also simply call a sub like a method by including the & sygil:

    sub is-even(Int $n) { $n %% 2 }
    say 4.&is-even;  # True
    

    It's just syntactic sugar, of course, but I've done it a few times when it looked more readable than simply calling the sub.

    (I know you're “not looking for workarounds or alternate solutions”, but you posted some yourself, so I thought, why not?)

    0 讨论(0)
  • 2021-02-19 05:34

    There's syntactic sugar for this - augment:

    use MONKEY-TYPING;
    
    augment class Int {
        method is-even() returns Bool:D {
            return False if self % 2;
            return True;
        }
    }
    

    Augmenting a class is considered dangerous for two reasons: First, action at a distance, and second, because (as far as I'm aware), there's potential for undefined behaviour deoptimization as it might leave various method caches in an invalid state.

    Thus, the requirement for providing the MONKEY-TYPING pragma before you're allowed to use it.

    As an aside, note that is-even could be written more compactly as self %% 2.

    0 讨论(0)
  • 2021-02-19 05:37

    Huh, this works, which I thought I'd tried before and I like better than what I presented in the question.

    Int.^add_method( 'is-even', method () returns Bool:D {
        return False if self % 2;
        return True;
        } );
    
    say 137.is-even;
    

    I'm not sure this should work, though. The add_method docs says we should only do this before the type is composed. If I call Int.^methods the is-even doesn't show up. Still, it seems to be callable and doing the right thing.

    Lexical methods

    Playing more, I figured I could make a method that's not attached to any class and call that on an object:

    my &is-even = method (Int:D :) returns Bool:D { self %% 2 };
    

    This constructs a Callable (look at &is-even.WHAT). In the signature, I constrain it to be a definite Int value (Int:D) but don't give it a name. I add the colon after type constraint to note that the first argument is the invocant. Now I can apply that method to any object I like:

    say 137.&is-even;
    say 138.&is-even;
    say "foo".&is-even;  # works, although inside is-even blow up
    

    This is nice in a different dimension since it's lexical, but not nice in that an object of the wrong type might call it. The error shows up after it thinks it has the method to dispatch to.

    0 讨论(0)
提交回复
热议问题