6

I was wondering how to mix in an abstract role into a variable in runtime. Here's what I came up with

role jsonable {
    method to-json( ) { ... }
}

class Bare-Word {
    has $.word;
    method new ( Str $word ) {
        return self.bless( $word );
    }
}

my $that-word = Bare-Word.new( "Hola" ) but role jsonable { method to-json() { return "['$!word']"; } };

However, this throws an (perfectly reasonable) error:

$ perl6 role-fails.p6
===SORRY!=== Error while compiling /home/jmerelo/Code/perl6/dev.to-code/perl6/role-fails.p6
Attribute $!word not declared in role jsonable
at /home/jmerelo/Code/perl6/dev.to-code/perl6/role-fails.p6:14
------> hod to-json() { return "['$!word']"; } }⏏;
    expecting any of:
        horizontal whitespace
        postfix
        statement end
        statement modifier
        statement modifier loop

$!word belongs to the class, so it is not available as such in the mixin declaration. However, but is simply a function call so the declared variable should be available inside, right? What would be the right syntax to access it?

Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
jjmerelo
  • 22,578
  • 8
  • 40
  • 86

1 Answers1

6

The right syntax would be $.word, which is basically short for self.word, so it uses the public access method.

But I think there are some typos and some misconceptions here. The typo (I think) is that .bless only takes named parameters, so instead of $word, it should be :$word (turning a positional to word => $word). Also, a role that defines but not implements a method, and then use the same name to implement a role with that name, doesn't make sense. And I'm surprised it doesn't generate an error. So get rid of it for now. This is my "solution":

class Bare-Word {
    has $.word;
    method new ( Str $word ) {
        return self.bless( :$word );  # note, .bless only takes nameds
    }
}

my $that-word = Bare-Word.new( "Hola" ) but role jsonable {
    method to-json() {
        return "['$.word']"; # note, $.word instead of $!word
    }
}

dd $that-word; # Bare-Word+{jsonable}.new(word => "Hola")

Hope this helps.

Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
  • 1
    You can use an abstract role `jsonable` (to be able to use it in type checks, for example), and implement it with an anonymous role: `my $that-word = (Bare-Word.new( "Hola" ) but role { method to-json() { return "['$.word']"; } }) but jsonable;` – moritz Jan 06 '18 at 19:32