Search code examples
metaprogrammingrakurakudo

How to add an attribute and its accessors in Raku using add_attribute()?


I have this program:

class Foo {
  has $.first;
}

my $a = Attribute.new(
          :name('$!second'),
          :type(Int),
          :package('Foo'),
          :has_accessor(True)
        );
Foo.^add_attribute($a);
Foo.^compose;

Foo.^attributes».say; # Mu $!first␤Int $!second␤

my $foo = Foo.new: :42first, :21second;

$foo.second.say; # P6opaque: no such attribute '$!second' on type Foo in a Foo when trying to get a value

The attributes method shows that the attribute has been added, creating an object apparently succeeds, yet when I try to access the $!second attribute I receive an error.

What am I missing?


Solution

  • What am I missing?

    Looks like you're not missing anything. Looks like a bug to me.

    At this stage of RakuAST development, I don't think it will get fixed.

    If you're really into building classes programmatically, I'd suggest you start looking into using RakuAST.

    Documentation is still mostly absent, but there's a powerful .AST method that you can run on sample code, that will produce the RakuAST statements needed to create that code. For example:

    $ raku -e 'say Q|class A { has $.a; has $.b }|.AST'
    RakuAST::StatementList.new(
      RakuAST::Statement::Expression.new(
        expression => RakuAST::Package.new(
          declarator => "class",
          name       => RakuAST::Name.from-identifier("A"),
          body       => RakuAST::Block.new(
            body => RakuAST::Blockoid.new(
              RakuAST::StatementList.new(
                RakuAST::Statement::Expression.new(
                  expression => RakuAST::VarDeclaration::Simple.new(
                    scope       => "has",
                    sigil       => "\$",
                    twigil      => ".",
                    desigilname => RakuAST::Name.from-identifier("a")
                  )
                ),
                RakuAST::Statement::Expression.new(
                  expression => RakuAST::VarDeclaration::Simple.new(
                    scope       => "has",
                    sigil       => "\$",
                    twigil      => ".",
                    desigilname => RakuAST::Name.from-identifier("b")
                  )
                )
              )
            )
          )
        )
      )
    )