Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does foo(&nil) behave differently than foo(&"not a proc")?

I found out from heckle that

[1, 2, 3].each(&nil)

doesn't cause any errors - it just returns an enumerator.

By contrast,

[1, 2, 3].each(&"")

raises

TypeError: wrong argument type String (expected Proc)

Also, &nil causes block_given? to return false

def block_given_tester
  if block_given?
    puts "Block given"
  else
    puts "Block not given"
  end
end

block_given_tester(&nil) # => Block not given

It's not because NilClass implements to_proc - I checked the RDoc.

I can understand why it'd be nice to have &nil, but I'm not sure how it's done. Is this just one of the ways nil has special behavior not shared by other objects?

like image 917
Andrew Grimm Avatar asked Sep 14 '11 02:09

Andrew Grimm


1 Answers

The answer can be found by looking at Ruby's source code.

Ruby 1.8:

Look at the function block_pass in the file eval.c. Note that it treats nil specially from Proc objects (the macro NIL_P). If the function is passed a nil value, it evaluates an empty block (I think) and returns. The code right after it checks whether the object is a Proc object (the function rb_obj_is_proc) and raises the exception "wrong argument type (expected Proc)" if it isn't.

Ruby 1.9.2:

Look at the method caller_setup_args in the file vm_insnhelper.c. It converts the proc with to_proc only if it is not nil; otherwise, the type conversion and type check are bypassed.

like image 193
Peter O. Avatar answered Nov 15 '22 10:11

Peter O.