Reputation: 1309
I have been trying to inherit the Proc
class in Ruby. I know there are tons of other ways I could implement my class without actually inheriting Proc
, but now I want to know out of curiosity.
I want a class that can be instantiated without a block passed as an argument, but it just won't work (this seems to be the reason). It is clear that you can't instantiate an actual Proc
without a block (not even with a proc
or lamba
):
Proc.new proc {|x| 2 * x } # => ArgumentError: tried to create Proc object without a block
Proc.new lambda {|x| 2 * x } # => ArgumentError: tried to create Proc object without a block
I assumed that overriding initialize
might just do the trick, but actually even overriding new
won't do:
class MyClass < Proc
def new *args, &block
super { |x| 2 * x }
end
def initialize *args, &block
super { |x| 2 * x }
end
end
MyClass.new { |x| 2 * x } # => everything is fine
MyClass.new "hello" # => ArgumentError: tried to create Proc object without a block
Is there any way (from within Ruby) to go around that restriction in proc.c? Or any elegant workaround?
Upvotes: 3
Views: 711
Reputation: 369556
super
without an argument list means "pass the original arguments along". In this case, the original argument is the string "hello"
, which is passed along to Proc::new
, but that doesn't take an argument!
The fix is to explicitly pass along no arguments:
class MyClass < Proc
def self.new(*)
super() {|x| 2 * x }
end
end
m = MyClass.new "hello"
m.(23) # => 46
Apparently, a block doesn't count as an argument list. You learn something new every day.
Upvotes: 5