Skip to main content

Ruby: A Python Programmer's Perspective Part IV

This is a somewhat random list of things that were interesting or surprising to me when I read Ruby for Rails. The previous post in the series is Ruby: A Python Programmer's Perspective Part III.

It's possible to add methods directly to an object instead of to a class:
>> obj = Object.new
=> #<Object:0x348c44>
>> def obj.talk
>> puts "Hi!"
>> end
=> nil
>> obj.talk
Hi!
=> nil
The methods are attached to what's called a singleton class. There is a singleton class that is associated with every object:
You can think of an object's singleton class as an exclusive stash of methods, tailor-made for that object and not shared with other objects--not even with other instances of the object's class
Class methods are similarly methods that are attached to the singleton class of an object of type Class.

There's even this weird syntax to attach additional methods to a class's singleton class:
?> class << C
>> def f2
>> puts 'f2'
>> end
>> end
=> nil
>>
?> C.f1
f1
=> nil
>> C.f2
f2
=> nil
It's possible in Python to attach methods directly to an object in Python too, but there is no formal notion of a singleton class. However, every object in Python does have a __dict__ which is a dict containing all the state and methods for that object:
>>> class C:
... def f(self): pass
...
>>> c = C()
>>> c.foo = 'bar'
>>> c.__dict__
{'foo': 'bar'}
>>> C.__dict__
{'__module__': '__main__', '__doc__': None, 'f': <function f at 0x6fef0>}
Moving on--you can inject a module's methods directly into an object:
obj = Object.new
obj.extend(SomeModule)
obj.some_method
Here's a useful way to inspect the class hierarchy:
?> class D < C
>> p ancestors
>> end
[D, C, Object, Kernel]
=> nil
In Ruby, singleton classes of class objects are sometimes called metaclasses. This is confusingly different from metaclasses in Python. In Python, a metaclass is the class (aka type) of a class. Hence, Python would call the Ruby class named Class a metaclass, whereas in Ruby, the metaclass of a class named C is an anonymous container for the class methods of C. Does your brain hurt yet? ;)

Ruby has a global named $SAFE:
It's very difficult to clean up user input...to the point where you can feel safe about running eval on it. Ruby maintains a global variable called $SAFE, which you can set to a higher number (on a scale of 0 to 4) to gain protection from dangers like rogue file-writing requests. $SAFE makes life with eval a lot safer. Still, the best habit to get into is the habit of not using eval. [p. 348]
You can break into an object's private data using instance_eval:
>> class C
>> def initialize
>> @x = 1
>> end
>> end
=> nil
>>
?> c = C.new
=> #<C:0x360718 @x=1>
>> c.instance_eval { puts @x }
1
=> nil
Here's a fun way to inject methods dynamically into a class:
>> Object.class_eval { define_method("foo") { puts 'hi' } }
=> #<Proc:0x0035b100@(irb):15>
>> obj = Object.new
=> #<Object:0x3599cc>
>> obj.foo
hi
=> nil
Unlike Python, JavaScript, and Scheme, you don't get closures just by nesting functions:
?> def f
>> def g
>> puts a
>> end
>> a = 1
>> g
>> end
=> nil
>>
?> f
NameError: undefined local variable or method `a' for main:Object
from (irb):29:in `g'
from (irb):32:in `f'
from (irb):35
That's because method scopes don't stack on top of one another. However, you can create a closure using Proc.new:
>> def f
>> a = "hi"
>> g = Proc.new do
?> puts a
>> end
>> g.call
>> end
=> nil
>>
?> f
hi
=> nil
I think I like the Scheme approach better.

Proc objects handle arguments in a different way than methods do. It's sloppier--more like JavaScript and Perl:
>> def f(x)
>> p x
>> end
=> nil
>>
?> f(1, 2, 3)
ArgumentError: wrong number of arguments (3 for 1)
from (irb):56:in `f'
from (irb):56
>>
?> p = Proc.new {|x| p x}
=> #<Proc:0x0033a414@(irb):58>
>>
?> p.call(1, 2, 3)
(irb):58: warning: multiple values for a block parameter (3 for 1)
from (irb):60
[1, 2, 3]
=> nil
Notice that calling a proc with the wrong number of arguments resulted in a warning instead of an exception and that all the arguments were pushed into a list in order to fit into one parameter.

Here's another example of this. Notice how Ruby will or will not unpack a list depending on context:
>> [[1, 2]].each {|x| p x}
[1, 2]
=> [[1, 2]]
>> [[1, 2]].each {|x, y| p(x, y)}
1
2
=> [[1, 2]]
I suspect this might be convenient, but I wonder if it occasionally bites unsuspecting programmers.

The lambda keyword lets you create an anonymous function. A lambda is an object of class Proc. However, lambdas and Proc.new behave differently when it comes to the return statement:
>> def return_test
>> l = lambda { return } # This return exits the lambda.
>> l.call
>> puts "Still here!"
>> p = Proc.new { return } # This return exits return_test.
>> p.call
>> puts "You won't see this."
>> end
=> nil
>>
?> return_test
Still here!
=> nil
The book says:
The matter of how Proc objects, code blocks, and lambdas related to each other has been, and still is, in a certain amount of flux. Don't be surprised if you see differences...from one version of Ruby to another. [p. 355]
To confuse things further:
It's worth mentioning that lambda has a synonym: proc. However, because proc and Proc.new look and sound so similar, but don't do exactly the same thing, Matz has agreed in principle to phase out proc, leaving just Proc.new and lambda. [p. 356]
Code blocks are not instances of Proc. They exist only in the syntax of Ruby. There is no such thing as a Block class or a Block object. However, you can convert a code block into a Proc object.

Ruby also supports bound methods:
>> class C
>> def f
>> puts 'f'
>> end
>> end
=> nil
>>
?> c = C.new
=> #<C:0x326a7c>
>> my_f = c.method(:f)
=> #<Method: C#f>
>> my_f.call
f
=> nil
You can also unbind and rebind a bound method to another instance.

Here's something I personally haven't seen in any other language. You can capture the act of subclassing a class, mixing in a module, or adding a method to a class as a runtime event. For instance, ActiveRecord in Ruby on Rails uses this functionality. Anytime someone subclasses ActiveRecord::Base, it captures the event (by defining a class method called "inherited") and adds the class to a list named "@@subclasses".

To alias a function under a new name, use the alias keyword: "alias :old_name :new_name". This is interesting, because in Python, you would just write "old_name = new_name". In Python, it's mandatory to use parenthesis when you call a function, so "old_name = new_name" is no different than saying "a = b" if a and b are both ints. The same isn't true of Ruby because "old_name = new_name" is essentially like "old_name() = new_name()" which doesn't even make sense. It's not a big deal, but it's just interesting to note that by making parenthesis non-mandatory, it leads to having an alias keyword. It also leads to writing "my_proc.call" instead of "my_proc()".

Everyone knows Ruby's string interpolation syntax: "Foo: #{bar}". However, Ruby also appears to support Python-like string interpolation:
>> puts "I weigh %.2f pounds." % 205.3
I weigh 205.30 pounds.
Ruby returns the value of the last expression encountered in the function. This is convenient if you don't want to have to explicitly type "return". However, I think it can lead to some unexpected results. Namely, unless a function documents what it's going to return, you should just assume it's going to return garbage:
def do_something
# Doing something.
5
end

def print_name(name)
puts "Name is #{name}"
do_something
end

def talk_to_user
puts "What's your name?"
name = gets
print_name(name)
end

talk_to_user
In the above code, talk_to_user will return 5 even though 5 has absolutely nothing to do with talk_to_user. In Python, if you don't explicitly "return" something, the function will return None by default.

Okay, that's it. If you've made it this far, thanks for reading!

Comments

rgz said…
Why I have mentioned many times that optional parens are more that just a nicety of the language, they are a result of many layers of language abstraction.

I'm somewhat amazed at how Python and Ruby are so fundamentally different and still so similar in syntax (superficially), code structure and programming approach.
> Why I have mentioned many times that optional parens are more that just a nicety of the language, they are a result of many layers of language abstraction.

I do really like the fact that in Ruby, you can just use "foo" as if it were a local variable, whereas actually it's a method that might be doing something interesting.

Python can do this too, but setting up properties is just a bit harder in Python, and there's the whole "self." bit.
Ooo, I like this idiom:

def messenger
@messenger ||= StringIO.new
end

Now you can access messenger without using @, and it'll get initialized on first use.

Note that StringIO is a string buffer in both Ruby and Python ;)
Ugh, I keep typing %[a b c d] when I mean to type %w[a b c d]. The first creates a string "a b c d". The second creates an array ["a", "b", "c", "d"]. Since an array and a string are somewhat similar, this is a nasty bug to track down, especially since "abcd"[0] is not the same as ["a", "b", "c", "d"][0], but it still works.
I think I like Python's approach to modules, packages, and modularity. In Python, each module can import whatever it wants, but it really only affects its own namespace. In Ruby, any file can "require 'foo'", and that might make "Foo" available in every other file.
Here is the Ruby idiom for globbing:

Dir[File.expand_path("#{File.dirname(__FILE__)}/../app/controllers/*.rb")]
If you have a class C with a constant A, you write C::A, whereas in Python you'd write C.A. I think this means Ruby uses "." only for methods, but uses "::" for namespace traversal. Python uses "." for both.
"extend" adds the instance methods from a module to one object. You often use "extend" to add instance methods to a class object as class methods.

"include" adds the instance methods from a module to an entire class. You often use "include" to add instance methods to a class as instance methods.

Hence, I keep seeing code that does:

...
module Methods
def self.included(klass)
klass.class_eval do
extend ClassMethods
include InstanceMethods
...

Where ClassMethods and InstanceMethods are separate modules being mixed into klass.
Docstrings in Ruby are just comments. In Python, they're specially-placed Python strings. That means in Python, I can use string interpolation to create the docstrings, whereas in Ruby, I can't. I do this sometimes in Python in order to string interpolate constant values into the docstring, or if I want piece together the docstring from a bunch of other strings. It also helps keep your docstrings DRY.
If you enjoyed this post, you may also enjoy: http://jjinux.blogspot.com/2009/08/rails-authlogic-code-review.html
Here's an example of using delegation:

delegate :link_to, :h, :to => 'ActionController::Base.helpers'
cattr_accessor and mattr_accessor are the same as attr_accessor but for classes and modules respectively.
You can create a new struct-like class very easily in Ruby using:

Rating = Struct.new(:name, :rating)

That's nice.
Ruby actually provides a non-local goto-like mechanism. In Ruby the keywords throw and catch are actually reserved for this purpose, while raise and rescue and the keywords for raising an exception and handling it.