This question concerns Perl's class syntax (new as of Perl 5.38.0). I have two classes, Rectangle and Square, with Square inheriting from Rectangle. They have different constructor arguments; Rectangle expects length & height while Square expects just side. My hope was that Square would be able to inject the length and height arguments into the constructor for Square's parent Rectangle object, based on side's value. Something akin to this, though the BUILD syntax from Object::Pad doesn't work:
class Rectangle
{
field $length :param;
field $height :param;
method get_area { return $length * $height; }
}
class Square :isa(Rectangle)
{
field $side :param;
BUILD {
my(%args) = @_;
my($side) = $args{'side'};
push(@_, length => $side, height => $side);
}
}
Here's my test script:
my($rect) = Rectangle->new(length => 5, height => 6);
say $rect->get_area();
my($sq) = Square->new(side => 5);
say $sq->get_area();
My expected output would be:
30
25
Is there a way to do this in 5.38.x? I'm thinking that the class implementation is simply not evolved enough yet to do this.
The only way to hook into instantiation provided by the new class feature are ADJUST blocks. ADJUST blocks have no access to the arguments of the constructor call. They can see $self and instance variables of their own package. Also they are invoked 'top down' (parent class first). So to make your example work you have to:
This results in
use v5.38;
use feature 'class';
class Rectangle
{
field $length :param = 0;
field $height :param = 0;
method set_length($arg) { $length = $arg }
method set_height($arg) { $height = $arg }
method get_area { return $length * $height; }
ADJUST {
say "in Rect ADJUST";
}
}
class Square :isa(Rectangle)
{
field $side :param;
ADJUST {
say "in Square ADJUST";
$self->set_height($side);
$self->set_length($side);
}
}
my($rect) = Rectangle->new(length => 5, height => 6);
say $rect->get_area();
my($sq) = Square->new(side => 5);
say $sq->get_area();
prints
in Rect ADJUST
30
in Rect ADJUST
in Square ADJUST
25
This feels like an ugly workaround to get past the limitations of the class feature as it is. I would not use it.
Another way to solve this would be to make the length and height attributes overridable by using accessor methods in Rectangle::get_area :
use v5.38;
use feature 'class';
class Rectangle
{
field $length :param = 0 ;
field $height :param = 0 ;
method get_length { $length }
method get_height { $height }
method get_area { return $self->get_length * $self->get_height; }
}
class Square :isa(Rectangle)
{
field $side :param;
method get_length { $side }
method get_height { $side }
}
my($rect) = Rectangle->new(length => 5, height => 6);
say $rect->get_area();
my($sq) = Square->new(side => 5);
say $sq->get_area();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With