Why override on OneClass.new as following code not cause infinite loop?

class A
  def initialize
    puts "foo"
  end

  def self.new
    new.tap do |o|
      puts "bar"
      yield o
    end
  end
end

a = A.new
# => "foo"

a1 = A.new { |o| p o }
# => foo
# => bar
# => #<A:0x7fd9456aae60>

It’s seem like it only works when yield the new object to block, i guess the new object within the new method was tap into the block, something strange is happening, but i don’t understand why.

Thanks

Pretty sure it works since your normal initialize method creates a non-yielding new method. Since your custom .new method does yield, it first calls into the non-yielding variant, then goes into your #tap code which is why both foo and bar is printed.

The blockless and yielding overloads are separate in Crystal, unlike in Ruby. This is the main motivation behind making the formatter append a block parameter to the second overload automatically.

2 Likes

Actually, I knew override above, but the main reason I didn’t understand it before is that I didn’t realize that initialize creates a non-block version of new.

There is some cunning here.