Reputation: 575
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.
Upvotes: 5
Views: 161
Reputation: 3045
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.
class File
{
has $!filename;
}
class XmlFile is File
{
has $!filename;
submethod BUILD(:$!filename)
{
}
}
my XmlFile $XF = XmlFile.new(filename => "test.xml");
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 a class 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.
class XmlFile
{
has File $!file handles<some methods>;
...
}
Upvotes: 0
Reputation: 26969
You're halfway there. You have to make the correct two changes to your code:
class File {
has $.filename; # 1. Replace `!` with `.`
}
class XmlFile is File {
submethod BUILD(:$filename) { } # 2. Remove `!`
}
dd my XmlFile $XF = XmlFile.new(filename => "test.xml");
# XmlFile $XF = XmlFile.new(filename => "test.xml")
Replacing $!filename
with $.filename
in the File
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 the BUILD
signature in the XmlFile
class means you're no longer trying to reference a non-existent XmlFile
attribute and instead just passing a named argument.
Per Object Construction:
Due to the default behavior of BUILDALL and BUILD submethods, named arguments to the constructor
new
derived fromMu
can correspond directly to public attributes of any of the classes in the method resolution order, or to any named parameter of any BUILD submethod.
(There's that "public attribute" misnomer. It means "attributes with a matching public accessor".)
Upvotes: 4