Sunday Dec 14, 2008

The curious case of the Ruby T-Square operator.

 The "||=" operator is interesting, both in what it does as much as in how it's widely used in Ruby land.  The operator does not do what you would usually expect.  i.e.,

a ||= expr

is not the same as

a = a || expr

The evaluation happens to be 

a or a = expr

 and the difference is important in at least one use case [0]

As a little DTrace script will verify, this operator is not implemented is a method(or anywhere in Ruby land) and is intrinsic to the VM.   The reason is performance, and the fact that the entire expression does not have to be evaluated to yield a result when you're 'OR'ing:

"Ruby's Boolean operators are built into the language and are not based on methods: classes, for example, cannot define their own && method.  Ruby defines special true and false values but does not have a Boolean type. method. The reason for this is that Boolean operators can be applied to any value and must behave consistently for any kind of operand."

. . .

"Another reason that Ruby's Boolean operators are a core part of the language rather than redefinable methods is that the binary operators are "short-circuiting." If the value of the operation is completely determined by the lefthand operand, then the righthand operand is ignored and is never even evaluated."

 (From The Ruby Programming Language, 1st Edition by David Flanagan and Yukihiro Matsumoto.)


Assuming that variable "a" was not defined prior, then a = a || expr works a little differently than it would if the rvalue was assigned to an lvalue other than a.  That is, if a is not defined, then expr is assigned to a.  If however, a was not present in the lvalue and the rvalue looked the same(say the code looked like b = a || expr ), then the rvalue will fail to evaluate since "a" is not defined.

>> b = a || "Foo"
NameError: undefined local variable or method `a' for main:Object
        from (irb):2:in `binding'
        from C:/Program Files/NetBeans 6.5/ruby2/jruby-1.1.4/lib/ruby/1.8/irb.rb:150:in `eval_input'
        . . .
>> a = a || "Foo"
=> "Foo"
>>

This special operator finds popular usage not in logical "OR"s, but in variable assignment.  It's a Rubyism to instantiate instance variables in methods other than constructors.  

From mongrel_rails (version 1.1.5):

    def config_keys
      @config_keys ||=
        %w(address host port cwd log_file pid_file environment docroot mime_map daemon debug includes config_script num_processors timeout throttle user group prefix)
    end

This deferred assignment is useful in general if your constructor contains many complex instantiations that need not be performed during object construction.  But in this case, it's just a Rubyism.  It's called lazy initialization[1].  There's also an easy patch to make that work transparently if you really like it[2].

There is another occasion to use this Rubyism:  when your method accepts a parameter with a default value that needs to be populated with a method call.  From Rails 1.1:

  def install(method=nil, options = {})
    method ||= rails_env.best_install_method?

It'd clutter the method definition line to have rails_env.best_install_method? all in the same place, and hence is a good way to produce readable code.

This Rubyism is not usable when nil or false are legal values for the variable being thus assigned.

 "For the purposes of all Boolean operators, the values false and nil are considered false. And every other value, including true, 0, NaN, "", [], and {}, is considered true."

 (From The Ruby Programming Language, 1st Edition by David Flanagan and Yukihiro Matsumoto.)

There's another interesting usage, to avoid the "nasty nils", as pointed out in the below comment by Mark Wilden, and here[4]

If you're too young to know what a T-Square is, see [3]

[0] http://dablog.rubypal.com/2008/3/25/a-short-circuit-edge-case

[1]  http://blog.jayfields.com/2007/07/ruby-lazily-initialized-attributes.html

[2] http://pillowfactory.org/2008/08/28/lazy_attr_accessor

[3] http://en.wikipedia.org/wiki/T-square

[4] http://hassox.blogspot.com/2007/10/ruby-default-argument-gotcha.html

A simple T-Square




About

prashant

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today