I've written them in quite a terse fashion. This is because when you're doing OO without any OO frameworks, you end up having to write a lot of these sort of little accessor subs, and making them as abbreviated as possible keeps you sane. Writing out the name sub in full might be:
sub name {
my $self = shift;
if (not defined $self->{name}) {
$self->{name} = $self->_build_name();
}
return $self->{name};
}
But if you're writing similar accessors for dozens of different attributes, it's nice to abbreviate them so they fit on a line each:
sub name { $_[0]->{name} //= $_[0]->_build_name }
sub colour { $_[0]->{colour} //= $_[0]->_build_colour }
sub owner { $_[0]->{owner} } # this one has no default
sub height { $_[0]->{height} //= 2.5 } # another way to provide a def
+ault
...;
Slight diversion...
The disadvantage of the second way of doing defaults (shown above) is it makes the default harder to override when you create a subclass. If the height had been defaulted via $_[0]->_build_height then when we decided to write a Pony::Shetland class, we could simply override _build_height to return a different default value (maybe 1.2?). But with the default 2.5 hard-coded into the height sub itself, we need to override height in Pony::Shetland.
Obviously, overriding the height sub in Pony::Shetland is perfectly possible. It's technically no more difficult than overriding _build_height. However, overriding _build_height rather than height seems preferable because OO code tends to be more maintainable when you're only overriding very small targeted bits of functionality.
As an example, let's assume that Pony::Shetland overrides height from Horse. Now somebody goes and releases a new version of Horse with a brand new feature. It allows:
my $aj = Horse->new(name => "Applejack");
my $metres = $aj->height( in => "metres" );
my $inches = $aj->height( in => "inches" );
my $hands = $aj->height( in => "hands" );
my $silly = $aj->height( in => "lightyears" );
Nice piece of new functionality, eh? However, Pony::Shetland overrides height, so the new functionality doesn't work there! There's something called the Liskov substitution principle that says anything that works with the base class should work with subclasses. So we've broken that principle.
If Pony::Shetland was just overriding _build_height, we would never have gotten ourselves into this quandary. The new height would still work in Pony::Shetland.
End of slight diversion!
Regarding //=... the // and //= operators were introduced in Perl 5.10. // is much the same as || but rather than testing the truthiness of the left hand value, it tests the definedness. The number 0 and the empty string are defined but false, so if you wanted to be able to have horses with a name "0", this distinction could be important.
$foo //= $bar is shorthand for $foo = ($foo // $bar), so it means the same as if (not defined $foo) { $foo = $bar }.
|