Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is `duplicable?` defined the way it is?

I come across this in Rails source code:

class Object
  def duplicable?
    true
  end
end

class NilClass
  begin
    nil.dup
  rescue TypeError    
    def duplicable?
      false
    end
  end
end

With this code, even after dup is removed from an object, that object responds to duplicable? with true.

I think it can be rewritten to a simpler code like:

class Object
  def duplicable?
    repond_to?(:dup)
  end
end

What is the merit of defining duplicable? using begin...rescue?

like image 812
久保圭司 Avatar asked Mar 16 '18 13:03

久保圭司


Video Answer


2 Answers

What is the merit of defining duplicable? using begin...rescue?

Ruby before 2.4 raised a TypeError when attempting to nil.dup:

$ rbenv local 2.3.0

$ ruby --version
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]

$ ruby -e 'p nil.dup'
-e:1:in `dup': can't dup NilClass (TypeError)
    from -e:1:in `<main>'

Starting with Ruby 2.4, nil.dup just returns itself:

$ rbenv local 2.4.0

$ ruby --version
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin15]

$ ruby -e 'p nil.dup'
nil

Putting the method definition inside rescue ensures that the method is only defined for Ruby versions which raise the TypeError.

I think it can be rewritten to a simpler code like: [...]

Simply checking whether the receiver responds to dup doesn't work, because nil – being an Objectdoes respond to dup, even in 2.3. The TypeError is (was) raised from within Object#dup:

VALUE rb_obj_dup(VALUE obj)
{
    VALUE dup;

    if (rb_special_const_p(obj)) {
        rb_raise(rb_eTypeError, "can't dup %s", rb_obj_classname(obj));
    }
    // ...
}
like image 132
Stefan Avatar answered Sep 21 '22 23:09

Stefan


nil responds to dup explicitly throwing the TypeError (which has, in turn, nothing to do with NoMethodError.) [Correction: had responded to dup before 2.4, credits go to @Stefan.]

NilClass.instance_method(:dup)
#⇒ #<UnboundMethod: NilClass(Kernel)#dup>

The goal is to respond to duplicable? with false unless NilClass#dup is overwritten by another monkey patcher in the city. [Correction: read “another monkey patcher” as “Matz” :)]

like image 29
Aleksei Matiushkin Avatar answered Sep 17 '22 23:09

Aleksei Matiushkin