7

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?

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338

1 Answers1

8

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.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
  • I assume you're looking at one of the 1.8 branches not one of the 1.9 branches. – Andrew Grimm Sep 14 '11 at 04:54
  • Yes, that's from Ruby 1.8, as it's the code I have available. I'm now downloading the code for Ruby 1.9.2 to see if anything has changed. – Peter O. Sep 14 '11 at 05:03