Nicolas Mattia
Nicolas Mattia

Reputation: 1309

Have a class inherit Proc in Ruby

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

Answers (1)

J&#246;rg W Mittag
J&#246;rg W Mittag

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

Related Questions