Constructor inheritance woes

Community Forums/Monkey2 Talk/Constructor inheritance woes

Leo Santos(Posted 2016) [#1]
This code:
Function Main()
	Print( "   " )
	Local test1 := New Entity()
	Local test2 := New AdvancedEntity()
End

Class Entity
	
	Method New()
		OnCreate()
	End
	
	Method OnCreate() Virtual
		Print( "A basic entity has been created" )
	End

End


Class AdvancedEntity Extends Entity

	Method New()
		Super.New()
	End

	Method OnCreate() Override
		Print( "Behold! An advanced entity has been created!!!" )
	End

End


Works as I expect in Monkey1 (If I remove the "Virtual" and "Override" keywords, of course), which means I get two different messages printed.

But in Monkey 2, when the Advanced entity test2 is created, OnCreate() from the Super class is called instead of the overridden method, resulting in the same message printed twice.

If instead of calling Super.New() you call OnCreate() from the AdvancedEntity constructor the correct message is printed.

This is super annoying, because it means not only I'll have to redefine the constructor for each extended class even if they're identical, which is already a drag, I'll have to make sure I call OnCreate() after calling Super.New() every time as well. Of course it's not an issue in this simple example, but...

I like Monkey1's behavior better!


marksibly(Posted 2016) [#2]
This is due to mx2 using 'real' c++ constructors, ie: this is what c++ does.

The logic here is that you shouldn't be able to call a method on an object that hasn't been constructed yet (and I generally agree with this).

However, I may yet switch back to the monkey1 way - there are other problems with using c++ ctors and they kind of limit the things I can do in mx2.

But the obvious question is: why not just get rid of OnCreate() and place construction code in the constructor? This has the added benefit of ensuring all superclasses are properly constructed before your class, a bit like having OnCreate automatically call Super.OnCreate before it runs.


Leo Santos(Posted 2016) [#3]
why not just get rid of OnCreate() and place construction code in the constructor?

Good question! Short answer is that I have no idea what I'm doing. :-)

Long answer is that I'm using this for an entity system where you always extend the base entity class with more "dedicated" entities, and I thought it would just be neat if all the code for the extended entities goes into "OnCreate", "OnUpdate", "OnRender", etc. methods, Mojo.app style. I like consistency! :-)

I do feel that it's counter intuitive that a method not explicitly called with "Super.MethodName()" ends up calling the Super class.
Thanks!


marksibly(Posted 2016) [#4]
Monkey1's App.OnCreate is not called by the App constructor though. In fact, it's there for code that can't or shouldn't be called in a constructor in the first place!

OnCreate style methods can be useful for situations where there's a 'lag' between when an object is created and when its 'usable'. For example...

Local actor:=New Actor
scene.AddActor( actor )
actor.OnCreate()

This will guarantee 'actor' is added to 'scene' before OnCreate is called - which may be important depending on your design. And of course, there may be a bunch of other setup stuff involving actor before OnCreate is called. Basically, OnCreate is used to signal to the actor that it's now 'part of the system' and can start behaving like an actor, which is (or at least may be) different from plain construction.

In the case of monkey1, OnCreate is called after your App object is created AND (after that) graphics and audio have been initialized. Similar idea, and it wouldn't work if App.New called App.OnCreate.

This is what I tend to use OnCreate for in general anyway...

> I do feel that it's counter intuitive that a method not explicitly called with "Super.MethodName()" ends up calling the Super class.

It is a bit I guess, but constructors are kind of special - they *must* be called in order for the object construct itself properly, as they also initialize fields to default values. They effectivel 'create the initial object state that all methods depend on.


Leo Santos(Posted 2016) [#5]
Got it. I'll just loop through all entities once the Engine is done Initializing, and I'll call entity.OnCreate() from there. That'll sidestep the issues I was running into (And it's a better design anyway...).
Thanks!


Gerry Quinn(Posted 2016) [#6]
The clue is that it's called OnCreate() instead of Create()!