Kain Nobel
Member
Good day everybody!
I recently came across a method inheritance bug in one of my scripts, between Game_Character's initialize and Game_Player's initialize. Basically, Game_Character defines initialize but that method is never hand-defined in Game_Player, nor is a super called for that method in the default scripts, nor the SDK.
Later on down the road, you've got SDK (still doesn't super Game_Player's [/i]initialize[/i] method), then you get to the MACL, in which the script RGSS.Character creates an alias for Game_Player's initialize. Simple mistake, some may never be bothered by it, others might've got problems from it in otherwise perfectly written scripts and never figured out why (or figured out it was the MACL and deleted the MACL).
What happens in this case is that aliasing a parent/child method, in which the child method never previously called a super for, breaks the inherited binding of the Parent <=> Child method. Still lost? Here, I've written an example.
Are you still following, do you understand?
The Question
With that all out of the way, how can you check if a method was previously defined with super called or not? Can it be checked at all within a re-opened method definition? What about externally? I need to know because this kind of thing is a little tricky, and creates errors harder to track than most other generic problems due to the whole inheritance issues. Also, I know I can alias a method then call a super again, but I'd rather know how to check if the super was called so I'm not reduntantly calling a super more than once.
I recently came across a method inheritance bug in one of my scripts, between Game_Character's initialize and Game_Player's initialize. Basically, Game_Character defines initialize but that method is never hand-defined in Game_Player, nor is a super called for that method in the default scripts, nor the SDK.
Later on down the road, you've got SDK (still doesn't super Game_Player's [/i]initialize[/i] method), then you get to the MACL, in which the script RGSS.Character creates an alias for Game_Player's initialize. Simple mistake, some may never be bothered by it, others might've got problems from it in otherwise perfectly written scripts and never figured out why (or figured out it was the MACL and deleted the MACL).
What happens in this case is that aliasing a parent/child method, in which the child method never previously called a super for, breaks the inherited binding of the Parent <=> Child method. Still lost? Here, I've written an example.
In this example, you'll see what I mean about the binding of the methods being broken... test it with lines 24, 25, 26 commented. After you've done that, un-comment 24, 25, 26 lines and run the test again. You should see what I'm talking about.
Child method aliased without super
The binding of the two methods are broken because Child never super defines inherited method from Parent. You can still alias in the scope of Parent, or the scope of Child, but you can see that they're not binded anymore.
This creates problems down the road, where future aliases to the Parent's method aren't going to bind to the Child's method. Basically, when Child first inherited this method, that became the methods' definition, and it aliases correctly, but the method is no longer inherited from Parent.
Child method aliased with super called
The binding of these two methods remains, since Child defined type with a call to super.
That means you can alias Parent's method and it'll carry over to Child's same method, with Child and Parent's aliases tagging along together in the Child method's scope.
Code:
#===============================================================================
# ** Parent / Child (Example 1)
#===============================================================================
# Parent :
# --------
#
# Initially created, type is defined with return value of 'parent'
#
# Child :
# -------
#
# Initially created inherting from parent, no super methods re-defined
#
#===============================================================================
class Parent
def type
'parent'
end
end
class Child < Parent
# def type
# super
# end
end
parent, child = Parent.new, Child.new
p parent.type, #=> "parent"
child.type #=> "parent"
#===============================================================================
# ** Parent / Child (Example 2)
#===============================================================================
# Child :
# -------
#
# Still inheriting from Parent, type method is now aliased
#
#===============================================================================
class Child < Parent
alias aliased_child_type type
def type
type = aliased_child_type
type += '\'s child'
end
end
p parent.type, #=> "parent"
child.type #=> "parent's child"
#===============================================================================
# ** Parent / Child (Example 3)
#===============================================================================
# Parent :
# --------
#
# Now this method is aliased from the Parent class.
#
#===============================================================================
class Parent
alias aliased_parent_type type
def type
type = 'I am the '
type += aliased_parent_type
end
end
p parent.type, #=> "I am the parent"
child.type #=> "parent's child"
Child method aliased without super
The binding of the two methods are broken because Child never super defines inherited method from Parent. You can still alias in the scope of Parent, or the scope of Child, but you can see that they're not binded anymore.
This creates problems down the road, where future aliases to the Parent's method aren't going to bind to the Child's method. Basically, when Child first inherited this method, that became the methods' definition, and it aliases correctly, but the method is no longer inherited from Parent.
Child method aliased with super called
The binding of these two methods remains, since Child defined type with a call to super.
That means you can alias Parent's method and it'll carry over to Child's same method, with Child and Parent's aliases tagging along together in the Child method's scope.
Are you still following, do you understand?
The Question
With that all out of the way, how can you check if a method was previously defined with super called or not? Can it be checked at all within a re-opened method definition? What about externally? I need to know because this kind of thing is a little tricky, and creates errors harder to track than most other generic problems due to the whole inheritance issues. Also, I know I can alias a method then call a super again, but I'd rather know how to check if the super was called so I'm not reduntantly calling a super more than once.