You may just want this code:
class A { has $.name is rw }
class B is A { submethod BUILD { self.name = 'foo' } }
TL;DR All attributes are private to avoid the "fragile base class" problem. One option among many is to call the method you setup in A.
Why does BUILD not see attribute from parent class?
Quoting the doc section Attributes within the Objects page of the Language category:
In Raku, all attributes are private, which means they can be accessed directly only by the class instance itself.
This way Raku avoids the "fragile base class" problem. Quoting Wikipedia with my added emphasis:
One possible solution is to make instance variables private to their defining class and force subclasses to use accessors to modify superclass states.
Raku does this.¹
Call the method you setup in A
This code looks natural:
class A { has $.name }
class B is A { submethod BUILD { $!name = 'foo' } }
Quoting again from the doc linked above:
While there is no such thing as a public (or even protected) attribute, there is a way to have accessor methods generated automatically: replace the ! twigil with the . twigil (the . should remind you of a method call).
Your code has done that -- you've written has $.name in A instead of just has $!name. So your code generates a .name method (public to any user of an instance of A, or a subclass, or class that mixes in A) as well as a $!name attribute (private to A).²
But you haven't used that accessor method. Here's one way to do that so your code works. It just needs a couple small changes:
class A { has $.name is rw } # Add `is rw`
class B is A { submethod BUILD { self.name = 'foo' } } # s/$!name/self.name/
say B.new # B.new(name => "foo")
is rw makes the public .name accessor method a read/write one instead of the default read only one.
self.name works where $!name does not. ($.name throws a different compiler error with an LTA error message. See Using %.foo in places throws, but changing it to self.foo works.)
Footnotes
¹ Raku does more too. Continuing to quote solutions listed by Wikipedia:
A language could also make it so that subclasses can control which inherited methods are exposed publicly.
Raku allows this.
Another alternative solution could be to have an interface instead of superclass.
Raku also supports this (via roles).
² Note that one can override the autogenerated method. At an extreme, using self.name in A or B might actually run a method in A that makes a cup of tea and returns "oolong" rather than doing anything with A's $!name:
class A {
has $.name = 'fred'; # Autogenerates a `method name` unless it's defined.
method name { 'oolong' } # Defines a `method name` (so it isn't generated).
}
my \a = A.new;
say a; # A.new(name => "fred")
say a.name; # oolong
Conversely, if an A object changes its $!name, doing so might have no effect whatsoever on the name of the next cup of tea:
class A {
has $.name = 'fred';
method name { 'rooibos' } # ignores `$!name`
method rename { $!name = 'jane' }
}
my \a = A.new;
say a; # A.new(name => "fred")
a.rename;
say a.name; # rooibos