Project

General

Profile

Actions

Feature #13129

open

Refinements cannot refine method_missing and respond_to_missing?

Added by matsuda (Akira Matsuda) almost 8 years ago. Updated over 3 years ago.

Status:
Assigned
Target version:
-
[ruby-core:79077]

Description

Refinements with method_missing and respond_to_missing? behaves very strangely.

class C; end

using Module.new {
  refine C do
    def x() p:x; end

    def method_missing(m, *args)
      m == :foo ? p(:fooo!) : super
    end

    def respond_to_missing?(m, include_private = false)
      (m == :foo) || super
    end
  end
}

C.new.x
p C.new.respond_to? :foo
C.new.foo

The script above doesn't respond_to :foo nor run :foo as expected.
Actually, the result differs between ruby versions.

% ruby -v t.rb
ruby 2.5.0dev (2017-01-14 trunk 57328) [x86_64-darwin15]
:x
false
t.rb:19:in `<main>': undefined method `foo' for #<C:0x007f90ca0fb240> (NoMethodError)

% ruby -v t.rb
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin15]
:x
false
t.rb:19:in `<main>': undefined method `foo' for #<C:0x007f80ae097780> (NoMethodError)

% ruby -v t.rb
ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin15]
:x
false
t.rb:19:in `<main>': undefined method `foo' for #<C:0x007fd89c83b518> (NoMethodError)

% ruby -v t.rb
ruby 2.2.6p396 (2016-11-15 revision 56800) [x86_64-darwin15]
:x
false
:fooo!

% ruby -v t.rb
ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-darwin15.0]
:x
false
:fooo!

% ruby -v t.rb
ruby 2.0.0p648 (2015-12-16 revision 53162) [x86_64-darwin15.6.0]
t.rb:4: warning: Refinements are experimental, and the behavior may change in future versions of Ruby!
:x
false
:fooo!

What I can tell is that method_missing was broken at somewhere in between 2.2 and 2.3, and respond_to_missing? has never worked correctly.

Updated by shyouhei (Shyouhei Urabe) almost 8 years ago

  • Status changed from Open to Assigned

Updated by shugo (Shugo Maeda) almost 8 years ago

  • Assignee changed from shugo (Shugo Maeda) to matz (Yukihiro Matsumoto)

Akira Matsuda wrote:

Refinements with method_missing and respond_to_missing? behaves very strangely.

class C; end

using Module.new {
  refine C do
    def x() p:x; end

    def method_missing(m, *args)
      m == :foo ? p(:fooo!) : super
    end

    def respond_to_missing?(m, include_private = false)
      (m == :foo) || super
    end
  end
}

C.new.x
p C.new.respond_to? :foo
C.new.foo

The script above doesn't respond_to :foo nor run :foo as expected.
Actually, the result differs between ruby versions.

I think the behavior of 2.3 or later is expected because *_missing are
indirect method calls.

Matz, what do you think of changing the behavior?

Actions #3

Updated by nobu (Nobuyoshi Nakada) almost 7 years ago

  • Tracker changed from Bug to Feature
  • ruby -v deleted (ruby 2.5.0dev (2017-01-14 trunk 57328) [x86_64-darwin15])
  • Backport deleted (2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN)
Actions #4

Updated by naruse (Yui NARUSE) almost 7 years ago

  • Target version deleted (2.5)

Updated by matz (Yukihiro Matsumoto) almost 7 years ago

  • Tracker changed from Feature to Bug
  • Target version set to 2.5
  • ruby -v set to ruby 2.5.0dev (2017-01-14 trunk 57328) [x86_64-darwin15]
  • Backport set to 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN

Currently, I feel negative about the proposal.

First, as Shugo commented, method_missing etc. are considered indirect method calls.
Second, mixing refinements (static rebinding) and method-missing (dynamic rebinding) are very complex and easily become complex.

This is not the final decision. You may be able to persuade me in the future. But this is my current opinion.

Matz.

Actions #6

Updated by matz (Yukihiro Matsumoto) almost 7 years ago

  • Tracker changed from Bug to Feature
  • Target version deleted (2.5)
  • ruby -v deleted (ruby 2.5.0dev (2017-01-14 trunk 57328) [x86_64-darwin15])
  • Backport deleted (2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN)

Updated by kch (Caio Chassot) over 3 years ago

I was just bit by this and took a while to figure out.

It's not immediately obvious that it should not work. My mental model for refinements is that it shouldn't be different from reopening the class directly, or including a module.

So, it fails my principle of least surprise as is.

I understand the complexity angle tho.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0