doc icon indicating copy to clipboard operation
doc copied to clipboard

Wording and clarification on the "Object orientation" page

Open uzluisf opened this issue 6 years ago • 3 comments

While reading this page, I was somewhat confused with the wording used and some assumptions made in some of the paragraphs. I was going to submit it as a PR but I figured this is probably implied from the text and a seasoned professional might picked them up easily. Thus I might be the one missing the connection and failing to see the big picture here.


Paragraph 1:

Mu.new calls method bless on its invocant, passing all the named arguments. bless creates the new object, and then walks all subclasses in reverse method resolution order (i.e. from Mu to most derived classes) and in each class checks for the existence of a method named BUILD. If the method exists, the method is called with all the named arguments from the new method. If not, the public attributes from this class are initialized from named arguments of the same name. In either case, if neither BUILD nor the default mechanism has initialized the attribute, default values are applied. This means that BUILD may change an attribute, but it does not have access to the contents of the attribute declared as its default; these are available only during TWEAK (see below), which can 'see' the contents of an attribute initialised in the declaration of the class.

  • Suggested: (i.e. from Mu to the most derived class calling Mu.new at the time)

With from Mu to most derived classes, it seems like bless will walk all the subclasses even if the subclass from which I'm instantiating precedes other subclasses. For example in,

class A {}
class B is A {}
class C is B {}
class D is C {}

say B.new(); 

bless will walk down only to class B and not all the way down to the most derived class, namely C and D in this case. I'm unsure if I got it right though.

  • What's the the default mechanism referring to?

  • Suggested: to the TWEAK method

Paragraph 2:

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. See an example of its use below.

This paragraph seems to imply that all the BUILD methods (from Mu to the most derived class) will be called first one after another and then the TWEAK methods will be called afterwards. For example, instead of (BUILD -> TWEAK) -> (BUILD -> TWEAK) -> (BUILD), (BUILD -> BUILD -> BUILD) -> (TWEAK -> TWEAK). However, from what I gather, first the BUILD and then the TWEAK method will be called per class from the less derived to most derived provided these methods exist.

Suggested:

After the BUILD method in a class has been called, a method named TWEAK, if existent, will be called with the named arguments that were passed to new. This is done by each class from the less derived to the most derived one. See an example of its use below.

Paragraph 3:

... Second, BUILD submethods can be used to run custom code at object construction time.

Can an example of the BUILD submethod running custom code (to validate arguments, for example) be provided?

Paragraph 4:

However this is considered poor practice, because it makes correct initialization of objects from subclasses harder.

What are the alternatives then? Use multi method new so as to leave the new method accepting named arguments untouched? Provide a different method and leave new untouched?

uzluisf avatar Feb 02 '19 20:02 uzluisf

I'm not sure I understood you properly. Basically Class D is C is B is A. A bless in D will walk all the way down to A, that's what it says. Probably "most derived" is not exactly right, but I understood it this way. In the second case, I don't understand it that way. All BUILD would be called before all TWEAKs. I guess we should provide examples of BUILD. In general it's better not to use new, as BUILD and TWEAK are called by default, while new is not. Use new only if you don't intend your class to be subclassed, mostly.

JJ avatar Feb 03 '19 08:02 JJ

class D is C is B is A. A bless in D will walk all the way down to A, that's what it says. Probably "most derived" is not exactly right, but I understood it this way.

This is the way I understand it: A bless in D will walk all the way down from the base class Mu to the most derived class, in this instance D. In this case, this sounds right because D is the most derived class so we both agree in this part. However, the problem is the same description (i.e. from Mu to most derived classes) is being applied to all classes from less derived to most derived. For example, it doesn't sound right to say in class C is B is A that a bless in C will walk all the way down from the base class Mu to the most derived class because it seems to imply that it's walking all the way down to the class D which is the most derived class. So a less ambiguous way of saying it is that a bless in C will walk all the way down from the base class Mu to the most derived class at the time new is invoked, i.e., in this case, C.

All BUILD would be called before all TWEAKs.

I figured this is just a matter of specificity ;-). At at per class level, all BUILD will be called before all TWEAKS. However, with several classes that inherit from one another, the BUILD and TWEAK methods of the less derived class will be called first, then the BUILD and TWEAK methods of the next less derived class, and so on. So if one is thinking of a single class, All BUILD would be called before all TWEAKs is absolutely fine. However, I was reading the docs with the idea of different classes with their own BUILD and TWEAK methods and that's where I misinterpreted the sentence. I thought all the BUILD methods in all the classes would be called first and then all the TWEAK methods.


Hopefully now you have a better idea of where I'm coming from :-)!

uzluisf avatar Feb 03 '19 22:02 uzluisf

see also docs issue https://github.com/Raku/doc/issues/1796

arkiuat avatar Oct 23 '25 01:10 arkiuat