Is there a way to assign instance variables declared in a super class, from a constructor in a sub class? I have gotten used to using BUILD() as constructor, but I am wondering if this is a good idea. I.e:
use v6;
class File
{
has $!filename;
}
class XmlFile is File
{
submethod BUILD(:$!filename)
{
}
}
my XmlFile $XF = XmlFile.new(filename => "test.xml");
The code above doesn’t work, prompting an error: "Attribute $!filename not declared in class XmlFile". Is it a matter of using the right accesser? Changing "!" to "." does not solve the problem.
You're halfway there. You have to make the correct two changes to your code:
Replacing
$!filename
with$.filename
in theFile
class generates a public accessor method (.filename
) in that class.(Note that attributes are technically always private to a class, i.e. always unavailable to other classes, even trusted ones. When you see the phrase "public attribute" it really means there's a "public accessor" that controls access to a corresponding underlying private attribute.)
Removing the
!
twigil from theBUILD
signature in theXmlFile
class means you're no longer trying to reference a non-existentXmlFile
attribute and instead just passing a named argument.Per Object Construction:
(There's that "public attribute" misnomer. It means "attributes with a matching public accessor".)
If you would like it to remain private, you can always add it directly to the subclass as well. (Perhaps you don't control the class you are subclassing?) You will, of course, have to be careful about which methods do which things between your class and subclass.
You may also want to consider using a 'has a' relationship instead of a 'is a' relationship by making an attribute of
class XmlFile
that holds aclass File
depending on what you are trying to do.The handles trait makes delegation to another class a particularly easy and useful option to direct subclassing.