Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl6: Constructors in subclases

Tags:

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.

like image 450
Mikkel Avatar asked Jun 14 '17 14:06

Mikkel


1 Answers

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 from Mu 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".)

like image 83
Elizabeth Mattijsen Avatar answered Sep 30 '22 15:09

Elizabeth Mattijsen