Ruby advertises its “The Least Surprise” principle. If you are unsure about something on Ruby, you can guess and try, and it usually works, except for some quirks mentioned below.
If you prefer reading a tutorial before diving into Ruby, I would recommend why’s guide to Ruby, which may be outdated, but definitely poignant.
begin ... end while
begin "code executed" end while false
"code not executed" while false
This is really anti-intuitive. And the creator of Ruby said not using this.
Don’t use it please. I’m regretting this feature, and I’d like to remove it in the future if it’s possible.
– matz
Unfortunately, this feature still exists in Ruby 3.1.
Proc.new
The return
statement in proc created by Proc.new
will not only return control just from itself, but also from the method enclosing it.
def some_method
myproc = Proc.new {return "End."}
myproc.call
# Any code below will not get executed!
# ...
end
Well, you can argue that Proc.new
inserts code into the enclosing method, just like block.
But Proc.new
creates an object, while block are part of an object.
And there is another difference between lambda and Proc.new
.
That is their handling of (wrong) arguments.
Lambda complains about it, while Proc.new
ignores extra arguments or considers absence of arguments as nil.
irb(main):021:0> l = -> (x) { x.to_s }
=> #<Proc:0x8b63750@(irb):21 (lambda)>
irb(main):022:0> p = Proc.new { |x| x.to_s}
=> #<Proc:0x8b59494@(irb):22>
irb(main):025:0> l.call
ArgumentError: wrong number of arguments (0 for 1)
from (irb):21:in `block in irb_binding'
from (irb):25:in `call'
from (irb):25
from /usr/bin/irb:11:in `<main>'
irb(main):026:0> p.call
=> ""
irb(main):049:0> l.call 1, 2
ArgumentError: wrong number of arguments (2 for 1)
from (irb):47:in `block in irb_binding'
from (irb):49:in `call'
from (irb):49
from /usr/bin/irb:11:in `<main>'
irb(main):050:0> p.call 1, 2
=> "1"
BTW, proc
in Ruby 1.8 creates a lambda, while in Ruby 1.9+ behaves like Proc.new
, really confusing.
def
does not create closures.Closures are simple in Python:
def a(x):
def b():
return x
b()
This won’t work in Ruby.
def a(x)
def b
x
end
b
end
In Ruby, def
starts a new scope, without access to outer variables.
Only @var
and $var
can be accessed.
And no extern
keyword like in C.
In Ruby, lambda creates closure:
def a(x)
b = ->{ x }
b.call
end
Or define_method
:
def a(x)
define_method(:b) { x }
b
end
In Ruby 1.9, define_method
is not available in main Object, you can
use define_singleton_method
instead.