I was reading the source code for concurrent-ruby, and came across this line of ruby code.
def initialize(*args, &block)
super(&nil) # <--- ???
synchronize { ns_initialize(*args, &block) }
end
Can someone explain to me what it is supposed to do?
You have to start by understanding the &
operator as it's used here. See for example:
# The & here converts a block argument to a proc
def a(&blk)
end
# The & here converts the proc to a block
a(&Proc.new { true })
In the proc => block case, it is also capable of turning some objects into procs, for example:
# The symbol :class gets to_proc called here
[1].map(&:class)
Symbol#to_proc
produces the same functionality as follows
[1].map(&Proc.new { |x| x.class })
I'm not sure where the official documentation for this is (would welcome a pointer), but from testing it seems that &nil
does not actually pass any block to the method at all - it has no effect:
def a
block_given?
end
a {} # => true
a &:puts # => true
a &nil # => false
Now that that is explained, I can go on to say why it's needed.
If you omit parens with super
, all arguments are passed:
class A
def initialize arg
puts arg && block_given?
end
end
class B < A
def initialize arg
super
end
end
B.new(1) {}
# prints "true" - block and arg were both passed to super
If you don't want this to happen, you can manually pass arguments to super
. There is an issue with this, which I will get to after:
class A
def initialize arg1, arg2=nil
puts arg1 && !arg2
end
end
class B < A
def initialize arg1, arg2=nil
super arg1
end
end
B.new 1, 2
# prints "true" - arg1 was passed to super but not arg2
The problem is that although you can prevent positional and keyword args from being passed, this approach will not prevent a block being passed along:
class A
def initialize arg1
puts arg1 && block_given?
end
end
class B < A
def initialize arg1
super arg1
end
end
B.new(1) { }
# prints "true" - arg and block were both passed
For whatever reason, it is important here that it not happen, so they use an idiom I have not seen before but appears to get the job done: &nil
. It's essentially saying "pass nothing as a block". I guess if you don't do this then blocks are automatically forwarded.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With