http://www.perlmonks.org?node_id=11112794

Cow1337killr has asked for the wisdom of the Perl Monks concerning the following question:

I have been studying OOP and Moose.

I stumbled upon the RJBS presentation https://cdn.oreillystatic.com/en/assets/1/event/115/Moose%20is%20Perl_%20A%20Guide%20to%20the%20New%20Revolution%20Presentation%202.pdf "Moose is Perl".

I find it instructive to write Perl 5 programs showing each example found in presentations, blogs, and tutorials.

Here is one:

Perl 5 program: mip-087-001.pl

#!/usr/bin/perl # Program name: mip-087-001.pl Run it, thusly: See C++ comment below. + Moose is Perl (i.e., MIP or mip) presentation. # From https://cdn.oreillystatic.com/en/assets/1/event/115/Moose%20is% +20Perl_%20A%20Guide%20to%20the%20New%20Revolution%20Presentation%202. +pdf. # The code below is from https://www.perl.com/pub/2002/08/13/comment.h +tml/ use Acme::Comment type => 'C++', one_line => 1, own_line => 0; /* cd C:\2020-Raku-001\ perl C:\2020-Raku-001\Perl-scripts\mip-087-001.pl */ use strict; use warnings; use feature 'say'; local $| = 1; # Forces a flush. package Employee { use strict; use warnings; use Moose; use namespace::autoclean; # Code this instead of coding "no Moose;" a +t the end of the package block. has name => ( is => 'ro', isa => 'Str', required => 1, ); has title => ( is => 'rw', isa => 'Str', required => 1, ); sub name_and_title { my ($self) = @_; my $name = $self->name; my $title = $self->title; return "$name, $title"; } 1; # Magic true value. } package Employee::Former { use strict; use warnings; use Moose; use namespace::autoclean; # Code this instead of coding "no Moose;" a +t the end of the package block. extends 'Employee'; override name_and_title => sub { my ($self) = @_; my $old = super; return "$old (Former)"; }; # Slide #85. # The + says "we're overriding the definition in our superclass. Ever +ything stays the same # except for the provided changes." # Here, we give a default. If no value is given, the default is used, + which lets us satisfy the # "required" even when no value was given in the call to the construct +or. has '+title' => ( default => 'Team Member', ); 1; # Magic true value. } # Commented out. use Employee; my $peon = Employee->new({ name => 'William Toady', title => 'Associate Assistant', }); say $peon->name_and_title; # Get name_and_title. # Commented out. use Employee::Former; my $ex_peon = Employee::Former->new({ name => 'William Toady', title => 'Associate Assistant', }); say $ex_peon->name_and_title; # Get name_and_title. # Where is the test code? Answer: Slide #87. # Name this script mip-087-001.pl my $ex_peon2 = Employee::Former->new({ name => 'William Toady', }); say $ex_peon2->name_and_title; # ===> William Toady, Team Member (for +mer) __END__
Results:
William Toady, Associate Assistant William Toady, Associate Assistant (Former) William Toady, Team Member (Former)

I recently looked at Raku after the name change. (The Windows version is actually easy to install now.)

So, after reading much of the "Think Raku" book, I tried to write counterparts to my collection of Perl 5 RJBS presentation "Moose is Perl" programs.

Well,I am stuck. (I thought Moose was 1:1 Raku OOP. Boy, was I wrong.)

Raku program attempt: mip-087-001.raku

class Employee { has Str $.name is readonly is required; # "readonly" is the defaul +t. has Str $.title is rw is required; method name_and_title { my $name = self.name; my $title = self.title; return "$name, $title"; } } class Employee::Former is Employee { method name_and_title { my $old = callsame; return "$old (Former)"; } # Slide #85. # The + says "we're overriding the definition in our superclass. Ever +ything stays the same # except for the provided changes." # Here, we give a default. If no value is given, the default is used, + which lets us satisfy the # "required" even when no value was given in the call to the construct +or. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # Is there not a Raku counterpart for this? # has '+title' => ( # default => 'Team Member', # ); # My poor attempt: has $.title is default('Team Member'); # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX } # Commented out. use Employee; my $peon = Employee.new( name => 'William Toady', title => 'Associate Assistant', ); say $peon.name_and_title; # Get name_and_title. # Commented out. use Employee::Former; my $ex_peon = Employee::Former.new( name => 'William Toady', title => 'Associate Assistant', ); say $ex_peon.name_and_title; # Get name_and_title. # Where is the test code? Answer: Slide #87. # Name this script mip-087-001.raku my $ex_peon2 = Employee::Former.new( name => 'William Toady', ); say $ex_peon2.name_and_title; # ===> William Toady, Team Member (form +er)
Results:
William Toady, Associate Assistant William Toady, Associate Assistant (Former) The attribute '$!title' is required, but you did not provide a value f +or it. in block <unit> at C:\2020-Raku-001\Raku-scripts\mip-087-001.raku li +ne 60

Replies are listed 'Best First'.
Re: Raku question: "Moose is Perl", but it sure ain't Raku.
by tobyink (Canon) on Feb 11, 2020 at 20:36 UTC

    Here's an example using my latest plaything, MooX::Pression. Raku-like syntax, but it's Perl 5.

    use v5.14; use strict; use warnings; package Local { use MooX::Pression; class Employee { has name (type => Str, required => true); has title (type => Str, required => true); method name_and_title () { my $name = $self->name; my $title = $self->title; return "$name, $title"; } } class Employee::Former { extends Employee; factory former_employee; has +title = "Team Member"; around name_and_title () { my $old = $self->$next(@_); return "$old (Former)"; } } } my $peon = Local->new_employee( name => 'William Toady', title => 'Associate Assistant', ); say $peon->name_and_title; my $ex_peon = Local->former_employee( name => 'William Toady', title => 'Associate Assistant', ); say $ex_peon->name_and_title; my $ex_peon2 = Local->former_employee( name => 'William Toady', ); say $ex_peon2->name_and_title; __END__ William Toady, Associate Assistant William Toady, Associate Assistant (Former) William Toady, Team Member (Former)

    Of course, this uses Moo instead of Moose. If you prefer Moose...

    use MooX::Pression toolkit => "Moose";
Re: Raku question: "Moose is Perl", but it sure ain't Raku.
by holli (Abbot) on Feb 12, 2020 at 17:18 UTC
    The submethod BUILD is (indirectly) called by .bless. It is meant to set private and public attributes of a class and receives all names attributes passed into .bless. The default constructor .new defined in Mu is the method that invokes it. Given that public accessor methods are not available in BUILD, you must use private attribute notation instead.
    C&P, straight from the docs
    class C { has $.attr; submethod BUILD (:$attr = 42) { $!attr = $attr }; }; C.new.say; C.new( attr => 666 ); # 42 # 666
    Edit:
    The difference between BUILD and TWEAK (as mentioned by anonymous monk below) is, that the former happens while the object is constructed, whereas TWEAK happens after that, when the object has been fully constructed.


    holli

    You can lead your users to water, but alas, you cannot drown them.
      class A { has $.a; method TWEAK(:$!a = "foo") { } } dd A.new; # A.new(a => "foo") dd A.new(a => "bar"); # A.new(a => "bar")
Re: Raku question: "Moose is Perl", but it sure ain't Raku.
by duelafn (Parson) on Feb 12, 2020 at 12:46 UTC

    There may be a better way, but you can do this by overriding new (and removing the title attribute from Employee::Former):

    class Employee::Former is Employee { method new(*%params) { %params<title> //= 'Team Member'; return callwith(|%params); } method name_and_title { my $old = callsame; return "$old (Former)"; } }

    Good Day,
        Dean

Re: Raku question: "Moose is Perl", but it sure ain't Raku.
by Anonymous Monk on Feb 11, 2020 at 18:58 UTC
    has $.title = 'Team Member';