Incorrectly using alias as super

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
Here's a script

class A def test p 'A' endendclass B < A alias :th_old_test :test def test th_old_test p 'B' endendVery simple: you have a class that does something, and you have a child class that inherits from it, and it does the same thing as its parent, along with some extra stuff. This is a common pattern.Now, I am treating the alias as a super. Because "test" is not defined in B, whatever method I'm aliasing is inherited.

So if you say

b = B.newb.testIt will show

Code:
AB
Now the problem really shows when you start aliasing more things

Code:
class A  alias :th_a_test :test  def test    th_a_test    p 'A2'    endend
Now we expect the code to read

Code:
AA2B
but in fact it does not.Because this is how aliasing works.

Alias is not super. Alias can behave like super under particular circumstances, but overall, you're going to get bitten if you treat alias like super as I did.

The solution is to use super where you actually need a super call...but now we have a new problem:

what happens when you are aliasing the same method multiple times, and you don't know whether super was called or not.
I don't know of a way to address that problem.

If a method did not call super, perhaps it is better to assume it was meant to replace its parent's definition and try to not have anything to do with the parent.

But I believe most of the times, people just forget to call super?
 
Last edited by a moderator:

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,513
Reaction score
3,203
First Language
Binary
Primarily Uses
RMMZ
I know a few of my scripts incorrectly do this too (alias rather then super)... silly mistake really... :(
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
There are reasons to justify the use of aliasing rather than super directly.


My rule of thumb is: never put super and alias in the same method.


That is, if you're calling super, just overwrite the method completely because the method wasn't meant to call its superclass' definition to begin with.


The reason why we alias is to preserve existing logic that we know nothing about (they could be default scripts, someone else's script, etc). Ideally, a script shouldn't need to know anything about the existing of other scripts in the first place beyond what it requires.


If we call super directly, we may be calling the superclass' definition multiple times because anyone could have added a super call in a previous alias. This is why I prefer to assume super is already being called if it needs to be called.
 
Last edited by a moderator:

_Shadow_

Tech Magician Level:
Moderator
Joined
Mar 2, 2014
Messages
4,078
Reaction score
2,654
First Language
Greek
Primarily Uses
RMMZ
Can'r resist....

[SIZE=13.63636302948px]
[/SIZE]
 

nio kasgami

VampCat
Veteran
Joined
May 21, 2013
Messages
8,949
Reaction score
3,042
First Language
French
Primarily Uses
RMMV
Alias and super are really bad enemy they don't like each other I always have problem to alias some stuff when a super method is employ so instead of using alias I have to overwrite the method because super do a mismatch with alias 

so the only advise I can give to people ..just not use Alias with a super...this provoke unnecessary bug and glicth in your scripts
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
That is the similar problem I got from my battle system with the Luna Engine

if B is completely new class which doesn't exist in default script... I would like to call super instead of alias

Edit :

Now I have a follow up question

in Game_Actor and Game_Enemy it doesn't have "on_battle_end" method.

So... how if I'm going to add something "on_battle_end" method in Game_Actor?

Assumed that some commands will only valid for Game_Actor

If I use 'alias' the issue that you just said will likely to be appear

if I use 'super' that's mean overwrite the method.

Both will generate compatibility issues
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
Yes, that is the problem that I'm not sure how to solve.
 

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,682
Reaction score
3,003
First Language
Tagalog
Primarily Uses
RMVXA
hm... create a on_battle_end definition for Game_Actor adding your logic perhaps and make it call super?

That was how I always used super, if I define a method on the inherited class that is present in it's parent class...

so like

Code:
class Game_Actor  def on_battle_end    super #This will call the original on_battle_end    #add your other logic here  endend
if it wasn't defined on the superclass too (Game_Battler), then you might need to define it there too and just make it call super and do nothing else
 

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
I have a solution at the moment. But I'm not sure if it's a best practice though

You don't need to make alias or call super on Game_Actor

Instead, you should make an alias in Game_Battler instead and add additional check

Code:
class Game_Battler  alias theo_alias_on_battle_end on_battle_end  def on_battle_end    theo_alias_on_battle_end    if actor?      do_something_here    end  endend
 

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,682
Reaction score
3,003
First Language
Tagalog
Primarily Uses
RMVXA
this should work fine though since on_battle_end exist within Game_Battler anyway

class Game_Actor def on_battle_end super #This will call the original on_battle_end from Game_Battler #add your actor only logic here endendThis way, the original method from Game_Battler remains intact.Of course, assuming you don't have any other script that might be doing this too.

or all of them could just do

class Game_Actor def on_battle_end super end alias on_battle_end_one on_battle_end def on_battle_end on_battle_end_one #add your logic here endendNow it's still Actor only, and wouldn't probably cause any problems in case many scripts use this method since all the overwrite definitions of on_battle_end are calling super only so even if they overwrite one another, they're still basically doing the same thing.Downside is this will only work if all scripts that want to create actor only sequences for on_battle_end would use this method, if somebody does the first method, then there could be complications.

Anyway this are just alternatives. :)
 
Last edited by a moderator:

Another Fen

Veteran
Veteran
Joined
Jan 23, 2013
Messages
564
Reaction score
275
First Language
German
Primarily Uses
Awww, no day without learning something new I think... Thanks for pointing out that issue.

Perhaps an alternative could be this, if you really want to keep previous redefinitions:

(Similar to what Engr. Adiktuzmiko did)

class Game_Actor  unless instance_methods(false).include?:)on_battle_end)    define_method:)on_battle_end) { |*args| super(*args) }  end  # ...endEDIT: Fixed (implicit argument passing to the super call seems not to be allowed here)

However, I'm not sure if I would even use this myself...
 
Last edited by a moderator:

TheoAllen

Self-proclaimed jack of all trades
Veteran
Joined
Mar 16, 2012
Messages
5,592
Reaction score
6,522
First Language
Indonesian
Primarily Uses
RMVXA
Copy pasted from tsukihime's example with a little modification

class A  def test    p 'A'  endend  class B < A   unless instance_methods(false).include?:)test)    define_method:)test) { |*a| super }  end    alias :th_old_test :test  def test    th_old_test    p 'B'  endend B.new.test class A  alias :th_a_test :test  def test    th_a_test    p 'A2'    endend B.new.testNow I got an error
 

 
Last edited by a moderator:

Another Fen

Veteran
Veteran
Joined
Jan 23, 2013
Messages
564
Reaction score
275
First Language
German
Primarily Uses
Yes, I just found out that calling super within a block used for define_method is not allowed...

(Makes sense since the block itself is independent from any method).

EDIT: That was not even the case, just implicit argument passing seems not to be allowed here (as already stated in the error message... I do refuse to read sometimes...).

Learned something new again... :)

This should work (too):

Code:
class Game_Actor   unless instance_methods(false).include?(:on_battle_end)    def on_battle_end      super    end  end  # ...end
 
Last edited by a moderator:

IMP1

"haystack".scan(/needle/)
Veteran
Joined
Mar 6, 2014
Messages
61
Reaction score
44
First Language
English
Primarily Uses
RMVXA
what happens when you are aliasing the same method multiple times, and you don't know whether super was called or not.
When is this going to be a thing you need to know? If you're aliasing a method, you probably shouldn't need to call super.

As for your initial problem, this works for me:

class A def test p 'A' endendclass B < A def test super # Prints 'A' p 'B' endendclass A alias :th_old_test :test def test th_old_test p 'A2' endendb = B.newb.test # Calls B.test, which calls super, which is A.test (including its aliased version).This prints A, A2, B.

This is what super is for: calling the method with the same name in the parent class.

The only issue here is when you alias a method that has lots of subclasses calling it with super (as you may change their behaviour too).

if I use 'super' that's mean overwrite the method.
Why do you think this is the case?

The following is the "best" way to add fuctionality to a subclass, while still doing the functionality of the superclass.

class Game_Actor  def on_battle_end    super # This will call the original on_battle_end in Game_Battler    # This is where you add the additional functionality  endendEngr. Adiktuzmiko has given you the answer already.
 
Last edited by a moderator:

Another Fen

Veteran
Veteran
Joined
Jan 23, 2013
Messages
564
Reaction score
275
First Language
German
Primarily Uses
The main problem of this way is that it only works once. If you have two scripts that extend the method this way, one of them will inevitably get lost. Of course you can weigh the risk of this happening in praxis, with aliasing you keep out of harm's way - if it wasn't for the issue Tsukihime stated.

Something like this would be problematic:

class A  def test    p 'A'  endendclass B < A  def test    super # Prints 'A'    p 'B'  endendclass A  alias :th_old_test :test  def test    th_old_test    p 'A2'  endend class B  def test    super  # Extend test. Without knowing B already defines test, p 'B' is lost    p "B52"  endendb = B.newb.test # Calls B.test, which calls super, which is A.test (including its aliased version)
While this should work, it is quite messy:

Code:
class A  def test    p 'A'  endendclass B < A  unless instance_methods(false).include?(:test)    define_method(:test) { super() }  end  alias_method(:test_Bmod1, :test)  def test    test_Bmod1    p 'B'  endendclass A  alias :th_old_test :test  def test    th_old_test    p 'A2'  endend class B  unless instance_methods(false).include?(:test)    define_method(:test) { super() }  end  alias_method(:test_Bmod2, :test)  def test    test_Bmod2    p "B52"  endendb = B.newb.test # Calls B.test, which calls super, which is A.test (including its aliased version
 
Last edited by a moderator:

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,682
Reaction score
3,003
First Language
Tagalog
Primarily Uses
RMVXA
@Fen - Yeah, the first one I posted would only work if you only have one script doing that which is why I added a second method there

Code:
class Game_Actor  def on_battle_end    super  end  alias on_battle_end_one on_battle_end  def on_battle_end    on_battle_end_one    #add your logic here  endend
Now even if multiple scripts use this method, super will still be called (of course as long as you use different aliases).
 
Last edited by a moderator:

Another Fen

Veteran
Veteran
Joined
Jan 23, 2013
Messages
564
Reaction score
275
First Language
German
Primarily Uses
The problem I see is that

def on_battle_end
  super
end

overrides any previous definition of the on_battle_end method within the Game_Actor class. So while super will be called, any logic added previously to the method within the Game_Actor class is lost.
 
Last edited by a moderator:

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,682
Reaction score
3,003
First Language
Tagalog
Primarily Uses
RMVXA
Game_Actor doesn't have it by default, else we would have already just use alias right away.


Now if you have a script that added on_battle_end to Game_Actor to add their own logic, you'd need to edit that of course.


The idea of that method is that any script that would be doing this (aliasing a method that doesn't really exist in the child class) thing should follow that same method flow. It's more of for "how should you do your scripts to minimize problems".


And that's the idea of this thread right? How to avoid/minimize the problem that arises from trying to use alias on a method that isn't defined on that child class. The basic premise here is that the method isn't defined on that child class, so no problems with the overwrite.
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,564
Reaction score
3,846
First Language
English
The following is the "best" way to add fuctionality to a subclass, while still doing the functionality of the superclass.

class Game_Actor  def on_battle_end    super # This will call the original on_battle_end in Game_Battler    # This is where you add the additional functionality  endend
Arguably, the best way to maintain compatibility is to define

def some_method superendin all of the classes where you could potentially want to define custom behavior in child classes.As you say, scripts shouldn't have to know whether the original method calls super or not. If I'm just adding some extra logic to Game_Actor's on_battle_end (because it specifically should be for actors), I would be using an alias, and not super.

However, most people don't bother defining a method just to call super, and it would look really strange if you did.
 
Last edited by a moderator:

Engr. Adiktuzmiko

Chemical Engineer, Game Developer, Using BlinkBoy'
Veteran
Joined
May 15, 2012
Messages
14,682
Reaction score
3,003
First Language
Tagalog
Primarily Uses
RMVXA
It's also weird to alias an undefined method IMO. So I do prefer the 2nd method that I wrote which defines the method first and make it call super then make the alias method.
 
Last edited by a moderator:

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Couple hours of work. Might use in my game as a secret find or something. Not sure. Fancy though no? :D
Holy stink, where have I been? Well, I started my temporary job this week. So less time to spend on game design... :(
Cartoonier cloud cover that better fits the art style, as well as (slightly) improved blending/fading... fading clouds when there are larger patterns is still somewhat abrupt for some reason.
Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??

Forum statistics

Threads
105,860
Messages
1,017,038
Members
137,568
Latest member
invidious
Top