Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does anyone know why the TWEAK routine gets hit before the BUILD routine?

Minimal code:

 #!/usr/bin/raku

 class   Widget {
         submethod TWEAK(:$content, :$styles) {
                 say "t1\n";
         }
 }

 class   File is Widget {
         submethod BUILD() {
                 say "b1";
         }
 }

 my $xml = File.new();

And the output:

 t1

 b1

Relevant doc is at https://docs.raku.org/language/objects#Object_construction . I quote: "After the BUILD methods have been called, methods named TWEAK are called, if they exist, again with all the named arguments that were passed to new".

I'm using the version of rakudo that comes with Fedora 32 (rakudo-0.2020.02-1.fc32.x86_64 so probably February this year).

like image 584
Timothy Nelson Avatar asked Sep 28 '20 13:09

Timothy Nelson


2 Answers

A quick experiment adding a TWEAK and BUILD method to each example class where they are missing shows the order of calls is Widget::BUILD -> Widget::TWEAK -> File::BUILD -> File::TWEAK.

So I think the problem is the wording of the documentation "After the BUILD methods have been called, methods named TWEAK are called, if they exist, again with all the named arguments that were passed to new."

I think this should possibly be "After the BUILD methods have been called for each class, methods named TWEAK are called for that class, if they exist, again with all the named arguments that were passed to new."

This would then document what seems to be happening.

Note : since answering this question the documentation has been updated to reflect how the code is being run.

like image 69
Scimon Proctor Avatar answered Sep 18 '22 18:09

Scimon Proctor


TWEAK is called after BUILD.

However, subclasses still need to follow their parents classes' construction routines. Consider the following code:

class Foo {
  submethod TWEAK { say "Foo tweak" }
  submethod BUILD { say "Foo build" }
}

class Bar is Foo {
  submethod TWEAK { say "Bar tweak" }
  submethod BUILD { say "Bar build" }
}

Bar.new

If you run it, you can see what's going on pretty quickly:

Foo build
Foo tweak
Bar build
Bar tweak

Basically, the constructor methods of each class are not called until they've been called for the parent class, meaning at both build and tweak you can assume the parent class' attributes are properly initialized.

This is actually the reason that those methods need to be submethods, otherwise, if a parent class's build method references a private attribute, and the subclass inherits the parents method, you'll get an error since it will be called for both patent and child, but the child won't have access.

like image 25
user0721090601 Avatar answered Sep 18 '22 18:09

user0721090601