Ruby's Peculiarities
by Kyonides
This thread is all about some strange or unusual or certain features specific to the Ruby programming language. Some are object-oriented or functional characteristics while other are just internal specifications you should know about.
NOTE: Parent class and Super class are synonyms here.
Index
- It has 5 Types of Variables
- CONSTANTS are NOT as Static as their Counterparts in other Languages
- Classes and Modules are ALWAYS OPEN
- You only declare a class's parent class ONCE.
- The Very Existence of the Eigenclass or Metaclass in Ruby
- Modules have other ways to define NEW methods without explicitly specifying they belong to that module
- Ruby's Boolean Values
1. It has 5 Types of Variables
Languages like C offer 4, namely the block, the local, and 2 kinds of global variables.
C++ has the static and global static variables, too. The static variables behave in a similar way as Ruby's class variables.
[ Global static variables only exist on the C or C++ file where they were declared. ]
Ruby includes the instance variables, but lacks the global static variables.
From Ruby you get: $global, @@class, @instance, local and block.
Yes, the last 2 variables have no special symbol attached to them. The context determines which type of variable it is. Block variables can only live inside loops and iterators.
2. CONSTANTS are NOT as Static as their Counterparts in other Languages
In most languages, constants are always written in UPPERCASE. Sometimes their names might include some _underscore_ symbols as well.
In C or C++, you are NEVER supposed to alter a constant during execution.
On the contrary, Ruby does allow you do change them. This is specially true for Arrays [] and Hashes {}. Yet, you might want to use @instance variables instead. This would force you to create specific getter and setter methods in order to let you access or modify their values.
Then why would anybody let you alter a CONSTANT in the first place?
Well, the answer to this question might be found in our next point.
3. Classes and Modules are ALWAYS OPEN
Both classes and modules need a name, and it's a
Constant by nature.
Did you notice that I didn't write it in ALL CAPS?
That's because you're NOT supposed to. Only normal CONSTANTS need to follow that nomenclature. Class or Module names follow the same convention used in C++ for classes and namespaces, respectively.
Contrary to what happens to the other CONSTANTS' behavior, these Constants are not altered directly. You can only alter its contents, including its eigenclass or metaclass.
Just like it happens in other languages, you need to declare a class or module first.
Ruby:
class MyClass end module MyModule def self.my_method print "My method" end end
Call MyModule.my_method and a popup window will display this message: "My method"
Once they've been declared, they'll keep existing until the program finishes its execution.
Classes in Ruby can ONLY inherit methods declared in 1 parent class at a time. This limitation doesn't prevent the parent class to have its own superclass (a synonym) and this dynamic can repeat itself indefinitely. At the end, a class can inherit tons of methods from multiple classes as long as they all belong to the same family of classes.
This means a given class would only follow 1 single path up to the most basic class
Object in Ruby 1.8 and 1.9 or
BasicObject in Ruby 2.x and 3.x and that's it.
In C++ you can declare many friend classes simultaneously while Ruby cannot.
How might this affect the way Constants work in Ruby as I've mentioned in the previous point?
Well, these Constants cannot be closed. Not even once. You might finish defining a list of methods or singleton methods by placing the very last end keyword at the end of that script, but the class isn't closed internally. You can only close the definition stage, not the class itself.
You can easily confirm this. Just reopen that class or module in a separate script section and it will still work as long as you have not committed any errors.
That means I can now extend MyClass this way:
Ruby:
class MyClass def first_method print "First" end end
I can either paste it right below my previous declaration or on another script section, and nothing weird will ever happen.
What this proves is that Ruby classes and modules can be extended INDEFINITELY. (Or until you get out of RAM...)
And here comes another revelation that many old scripters loved to ignore:
4. You only declare a class's parent class ONCE
It doesn't mean that you can't declare it 1000 times if that's what you really want to do. The problem is you have NO NEED to do that, so why bother?
Ruby:
class MyChildClass < MyClass def second_method print "Second" end end
So far I have only declared 1 method MyChildClass, but don't forget you can also call MyClass#first_method as well. Why? Because it has been inherited from MyClass.
[ MyClass#first_method is not proper syntax, it's just a way Ruby programmers indicate where you can actually find that method. You're supposed to replace MyClass# with nothing if called from a class's internal method or with an actual object like @my_class.first_method ]
Still, what happens if later on I wanna add a third method? Especially on a different script...
Well, I can do this without facing any consequences:
Ruby:
class MyChildClass def third_method print "Third" end end
So why was I allowed to keep defining new methods if I NEVER redeclared the parent class?
The answer is very simple:
the class is still open and it DOES REMEMBER its superclass!
In Ruby 1.8 and 1.9 you're even allowed to change an existing class's parent class by redeclaring that superclass. Nonetheless, stop doing that! In later releases of the Ruby language it's considered a BUG and you're NOT ALLOWED to redeclare a parent class at all. Your session would crash immediately.
Of course, I know some people wouldn't care about changes applied to Ruby in later releases of the language, and I get it. The problem is that your code is supposed to follow a logic, an order. Changing a class's parent class definitely breaks that. Plus, it makes it way harder for other scripters to foresee such a change because they're used to the way the default scripts have been defined by the RPG Maker developers. If a scripter expects to access methods defined in the original parent class, the game will crash during test play.
Instead of changing the declaration of a class's superclass, just go create a new class with its own parent class, and case closed.
5. The Very Existence of the Eigenclass or Metaclass in Ruby
Because of the ability to declare singleton methods, methods that can only be accessed via the class or module itself instead of an instance (a copy) of a class, Ruby has the need to store all those class- or module-specific methods somewhere else. That other place is the
eigenclass or
metaclass.
By the way, eigen means "own" or "proper" in German, but in this particular case proper is the term we're looking for here. The eigenclass is the real class behind the actual class, if that makes any sense to you.
How do you access such an internal class?
Actually you might have already seen it in 2 different contexts: some scripter was altering a module or the Bitmap class.
You can rarely watch someone else altering some other class this way:
Ruby:
class << Bitmap end module << Graphics def width 640 end end
What has changed after accessing the eigenclass this way?
The changes are reduced to 1 simple concept: you can now define any methods or even Module class's methods like attr_accessor the same way you'd do it in any normal class. Yes, you can easily alias methods as well.
Except for the use of this << operator, everything else would look and behave as business as usual.
6. Modules have other ways to define NEW methods without explicitly specifying they belong to that module
This alternate method defining processes might not work with previously defined methods that included the self keyword.
Let's assume the default scripts included this module (or just add it to your script list):
Ruby:
module OldModule def self.method print "method" end end
And later on we try to redefine it or alias it this way:
Ruby:
module OldModule extend self def method print "method revisited" end end
Normally, we would use extend to extend a class or another module, but Ruby also allows us to extend the same module, too. Classes are not supposed to extend themselves.
Or let's use any of these 2 other ways:
Ruby:
module OldModule module_function def method print "method revisited" end end
Ruby:
module OldModule def method print "method revisited" end module_function :method end
There's a big chance that those new definitions might not work as expected. :S They can even be ignored by the language interpreter.
If you want to redefine them, you better use the self.method definition at all costs.
Or go straight to the eigenclass and redefine it there or simply go alias that method.
7. Ruby's Boolean Values
If you really ever wanted to find something terribly weird in a programming language, then the way Ruby implemented the boolean values might fit the bill.
In Ruby there are not 2 but 3 boolean values. The typical values are
true or
false. Yet, Ruby added
nil to this list. It treats it as a second false value. Most of the time at least.
Nil or nihil means nothing in Latin. Ruby only calls it nil, and it has the same basic usage as a null in C or C++ except for a little detail I'll discuss later on.
When is nil treated as an actual nil or non existing value?
That happens ONLY when you test a value against nil itself!
Ruby:
@variable == nil
If it returns true, it means it was really equal to nil in the first place. If you have never defined it before, then its current value is equal to nil. (It simply creates it then, and quickly sets its value to nil.)
nil is quite weird
If you define a variable the following way using the || or-operator:
Ruby:
@var = nil || false
It won't return a nil but a false value!
Defining a variable with an ||= if-not-yet-defined-set-value operator:
Ruby:
@var ||= nil
It becomes a redundant piece of code because that's exactly what Ruby would have done in the first place.
In languages like C and C++, you can use numeric values like 1 and 0 as replacements for true and false respectively. That's not possible in Ruby.
Ruby treats ALL NUMBERS (and objects except for false and nil) as true if you test them directly or via calling a variable.
Ruby:
if 0 print "Zero is treated as a truthy value." else print "You'll never read this line ever." end
Nevertheless, that won't be case if you explicitly test it against true:
Ruby:
if 0 == true print "Zero is treated as a truthy value... but not here!" else print "You'll read this line in no time. Guaranteed!" end
So numbers are treated and NOT treated as truthy values depending on the current context. :S
本贴来自国际rpgmaker官方论坛作者:kyonides处,因国际论坛即将永久关站,为了存档多年珍贵资料,署名转载到本论坛存档,由于官方帖子为英文原帖,需要中文翻译请点击论坛顶部切换语言为中文就可以将帖子翻译成中文浏览,方便大家随时查看,原文地址:
https://forums.rpgmakerweb.com/threads/rubys-peculiarities.180059/