From: brian ford Date: 2009-06-11T03:21:39+09:00 Subject: [ruby-core:23789] Re: Ducktyping interface Hi, On Sat, Jun 6, 2009 at 5:30 PM, Yehuda Katz wrote: > I should add that further examination reveals that people who make proxy > objects (Drb, Rails Association Proxy) expect that their respond_to? will > work correctly. If implementations were allowed to do internal checks only, > proxies would need to explicitly define all coercion methods, something they > do not currently do. > -- Yehuda To illustrate a bit more why I believe calling #respond_to? is an implementation detail, consider the following: $ irb >> fake = Object.new => # >> fake == 1 => false >> fake <=> 1 NoMethodError: undefined method `<=>' for # from (irb):3 >> fake.extend Comparable => # >> fake == 1 => nil >> def fake.<=>(other) >> 0 if other == 1 >> end => nil >> fake == 1 => true >> fake == 2 => nil And this is the MRI C code that performs the magic (compar.c): static VALUE cmp_eq(a) VALUE *a; { VALUE c = rb_funcall(a[0], cmp, 1, a[1]); if (NIL_P(c)) return Qnil; if (rb_cmpint(c, a[0], a[1]) == 0) return Qtrue; return Qfalse; } static VALUE cmp_failed() { return Qnil; } /* * call-seq: * obj == other => true or false * * Compares two objects based on the receiver's <=> * method, returning true if it returns 0. Also returns true if * _obj_ and _other_ are the same object. */ static VALUE cmp_equal(x, y) VALUE x, y; { VALUE a[2]; if (x == y) return Qtrue; a[0] = x; a[1] = y; return rb_rescue(cmp_eq, (VALUE)a, cmp_failed, 0); } In this case, MRI does not call #respond_to?. And I would argue that a more valid implementation in general is to dispatch and rescue if necessary, as this MRI code demonstrates. Thanks, Brian > > On Sat, Jun 6, 2009 at 5:12 PM, Yehuda Katz wrote: >> >> Matz, >> I've been working on adding some specs to RubySpec related to the >> ducktyping interface. I have observed the following behavior and want to >> know whether or not it's intentional. Let's use the #to_s coercion as an >> example: >> 1. If the object has a method #to_s, it's called. >> 2. If #to_s returns something that is not a String, a TypeError is >> raised. >> In MRI, the mechanism for determining if an object has a method #to_s is >> to call respond_to?. This means that even if the method does not exist, >> #to_s will get called, and fall through to #method_missing, if the >> #respond_to method returns true for :to_s. As a result, when using MRI, it >> is possible to implement the duck-typing interface without defining #to_s, >> but instead defining a combination of #respond_to? and #method_missing that >> returns a String. >> Is this intentional? Would it be ok for an alternative implementation to >> look up the #to_s method using an internal check instead of calling the >> user-defined #respond_to?, as MRI does? >> In other words, is the only "correct" way to enlist in Ruby coercion to >> define to_s explicitly, or is another correct way to define respond_to? and >> method_missing to return an appropriate response? >> -- >> Yehuda Katz >> Developer | Engine Yard >> (ph) 718.877.1325 > > > > -- > Yehuda Katz > Developer | Engine Yard > (ph) 718.877.1325 >