Perl 6: new, BUILD, BUILDALL…oh my!

First note: similarly to Perl 5, the new method has no special meaning in Perl 6! Let me get straight about this: Mu (the root class) provides a new method, but here is no special meaning about it and it is possible to call a constructor the way you like. What really matters are the following methods: bless, BUILD and BUILDALL, even if the latter two are submethods (i.e, special methods attached to the inheritance chain). The idea is as follows: 1) when new is invoked on a class object, the method produces a new instance of the same object the class defines, and this is performed via bless (do you remember Perl 5?); 2) the method new then invokes BUILDALL with all named parameters (essentially, an hash); 3) BUILDALL traverses the inheritance chain from the top to the bottom, and on each sub-instance invokes BUILD (of course, if does exist); 4) BUILD performs object initialization, usually the binding of values. The submethod BUILD is the intended hook for customizable object construction. The bless method is, in fact, the default constructor itself:
method bless(*%attrinit) {
    nqp::create(self).BUILDALL(Empty, %attrinit);
}
bless does create the instance and invokes BUILDALL on it, triggering the initialization across the inheritance chain. However, new does pretty much the same invoking bless or performing the very same action:
multi method new(*%attrinit) {
    nqp::if(
      nqp::eqaddr(
        (my $bless := nqp::findmethod(self,'bless')),
        nqp::findmethod(Mu,'bless')
      ),
      nqp::create(self).BUILDALL(Empty, %attrinit),
      nqp::invokewithcapture($bless,nqp::usecapture)
    )
}
It is possible to construct your own new constructor implementation based on bless, for instance:
class Person {
    has $.name;

     submethod BUILD( :$name ){
         say 'Person.BUILD invoked with ' ~ $name;
         $!name = $name;
     }

     method new( $person_name, $person_surname ){
        say 'Person.new invoked with ' ~ $person_name ~ ' and ' ~ $person_surname;
        my $name = $person_name ~ ' ' ~ $person_surname;
        self.bless( :$name );
    }

}
and if the positional new is invoked:
my $p = Person.new( 'Luca', 'Ferrari' );
it does result in the initialization structure being triggered:
Person.new invoked with Luca and Ferrari
Person.BUILD invoked with Luca Ferrari
In the case of a subclass, with a custom new, the inheritance chain is walked the right way from top to the bottom, but the positional constructor of the parent class is not used:
class Child is Person {
    has $.game;
    has $.age;

    submethod BUILD( :$name, :$game, :$age ){
        say 'Child.BUILD invoked with ' ~ $name ~ ' and ' ~ $game ~ ' and ' ~ $age;
        $!game = $game;
        $!age = $age;
    }

     method new( $name, $game, $age ){
         self.bless( :$name, :$game, :$age );
    }

}
and in fact, if the new instance is created with
my $c = Child.new( 'Diego', 'archery', 10 );
the result is:
Person.BUILD invoked with Diego
Child.BUILD invoked with Diego and archery and 10
Please note that when dealing with custom new the initialization by subclasses can be wrong, because the initialization itself performs two different paths (explicit new call, bless call). For more discussion, please see this issue and my comments.

The article Perl 6: new, BUILD, BUILDALL...oh my! has been posted by Luca Ferrari on June 1, 2018

Tags: perl6