I like it too - maybe when I split this I'll make it into a sticky and convert it into a general topic for discussing scripting concepts and asking questions.
Sorry, this is a lot longer than it really should be but I need to run right now and can't make it cleaner and prettier. I'll fix it up when I get back and make sure I didn't make any stupid mistakes.
In essence, you only need to put the condition on aliasing when you are aliasing an inherited method or a method in an otherwise hidden class (by hidden, I mean classes like Bitmap or the RPG module, etc). As far as I know, the following is why
I'll start with the F12 error; I find this part the hardest to explain, but basically, when F12 is pressed, the scripts in the Script Editor are re-interpreted, but the old interpretations aren't deleted in the way they would be if you closed and restarted the program. In other words, if this were our script list:
Sprite_Base
Window_Base
Scene_Base
For the purposes of describing the error, when we press F12 it is as if our script list were instead:
Sprite_Base
Window_Base
Scene_Base
Sprite_Base
Window_Base
Scene_Base
With the default scripts, it is perfectly fine to do that as there are no aliases or anything - all it's doing is redefining methods (to be the same that they were). Ie, it's equivalent to doing this:
class TDS
def cozziekuns
return "cozziekuns is awesome"
end
def cozziekuns
return "cozziekuns is awesome"
end
end
Redundant, but totally fine. If you call the cozziekuns method, you'll get "cozziekuns is awesome".
Now, let's take the situation where we alias it. So this:
class TDS
def cozziekuns
return "cozziekuns is awesome"
end
alias cozzie_new cozziekuns
def cozziekuns
return cozzie_new + " and also handsome"
end
end
The cozzie_new alias is identical to the original cozziekuns method, so what you get is "cozziekuns is awesome and also handsome". Great. Now in the case of F12, it is effectively:
class TDS
def cozziekuns
return "cozziekuns is awesome"
end
alias cozzie_new cozziekuns
def cozziekuns
return cozzie_new + " and also handsome"
end
end
class TDS
def cozziekuns
return "cozziekuns is awesome"
end
alias cozzie_new cozziekuns
def cozziekuns
return cozzie_new + " and also handsome"
end
end
But this is also totally fine - since cozziekuns was redefined again to be
def cozziekuns
return "cozziekuns is awesome"
end
before the second alias, it is only that which is aliased and so again, there is no recursion error. So that's why the "unless $@" was unnecessary in TDS's script. all of those base_stat methods were redefined back to normal in Game_Actor, so when aliased, it copied a method which had no reference to the alias name.
So, in essence, there is no reason to prevent the re-aliasing; it does no harm, it does no good; it does nothing. It aliases the exact same method it would have if it were the first time going through.
The problem arises when the original method is not redefined, and, as a result, the script aliases the method as altered (that has reference to the alias name). In other words, when this is effectively happening:
class TDS
def cozziekuns
return cozzie_new + " and also handsome"
end
alias cozzie_new cozziekuns
There, the alias is aliasing a method which calls it, ie, it is:
def cozzie_new
return cozzie_new + " and also handsome"
end
I think it's fairly obvious why this is a problem - when cozzie_new is called, it can never complete because it is recursive with no way to ever finish. As such you get the "F12 error", which is just that recursion error when it occurs as a result of the reinterpretation of the scripts.
In RGSS/2, there are at least two ways this can happen: (1) when you are aliasing a method in a "hidden" object; and (2) when you are aliasing an inherited method that is not already redefined in the class (ie, only defined in its superclass or inherited module).
The first scenario is pretty straightforward. Unlike the scripts in Scripts.rvdata, the "hidden" classes (Bitmap, Sprite, Window, etc.) aren't reinterpreted when you press F12. As such, this is what is effectively happening (something nonsensical):
class Bitmap # The actual method
def disposed?
# Whatever
end
end
class Bitmap # Your edits
alias ma_disposed_new disposed?
def disposed?
return false # if whatever
return ma_disposed_new
end
alias ma_disposed_new disposed? # Reinterpretation
def disposed?
return false # if whatever
return ma_disposed_new
end
end
As such, ma_disposed_new now calls itself without end when it is called and we have our recursion error.
For the second scenario, consider this:
class TDS
def cozziekuns
return "cozziekuns is awesome"
end
end
class Pacman < TDS
alias cozzie_new cozziekuns
def cozziekuns
return cozzie_new + " and also handsome"
end
end
class TDS
def cozziekuns
return "cozziekuns is a pumpkin"
end
end
t = TDS.new
p = Pacman.new
t.cozziekuns # -> "cozziekuns is a pumpkin"
p.cozziekuns # -> "cozziekuns is awesome and also handsome"
As you can see, the alias in Pacman retains the first definition of cozziekuns from TDS and naturally ignores the second (because the alias is created before the method is ever redefined). From this, it should be apparent why the "re-"interpretaton forced by F12 causes a problem. When it redefines the method in TDS, that has no impact on the Pacman class. As such, on the re-interpretation, when it gets to the alias, the current cozziekuns method in Pacman (since it had already been defined on the first interpretation and was not redefined since) is:
def cozziekuns
return cozzie_new + " and also handsome"
end
And so when the alias for cozzie_new happens, it is that method it aliases. So that is why the recursion error happens in that scenario.
Hopefully that explains when a fix is necessary and why.
The FixSo, in those scenarios is where the "unless $@" fix comes in - putting that will prevent the second aliasing, thus the alias name will still refer to the original definition and the recursion error will not occur. So, then the question is, what is $@ and why does "unless $@" prevent the recursion error?
The answer to that is easier. As Yeyinde mentioned, $@ contains the backtrace for the last exception raised.
When you first start the program, $@ will be nil, which is why "unless $@" will not prevent the initial aliases when first "loading" the scripts. The reason "unless $@" works to avoid stack errors later is because when F12 is pressed, it throws the "Reset" exception to tell the program to reset, which means that the second time the program interprets the scripts, $@ will have the backtrace for the Reset exception and therefore will not be nil, so the "unless $@" will be true and the alias will not happen again.
Personally, I think the reason hardly anybody knows why or when checking "unless $@" is necessary is precisely because it's checking $@ which, though reliable and related to the ultimate cause of the recursion error, doesn't really give the reader of the script much of an indication of why the recursion error happens in the first place. I think it's bad form to use it and instead use:
unless self.method_defined? (:alias_name)
It's a little uglier/longer and a little slower (totally negligible) than just checking $@, but I think it is more helpful.