Project

General

Profile

Actions

Bug #18385

closed

Refinement#import_methods(Enumerable) doesn't work

Added by zverok (Victor Shepelev) over 2 years ago. Updated over 2 years ago.

Status:
Closed
Target version:
-
[ruby-core:106483]

Description

Very simple to reproduce:

module M
  refine String do
    import_methods Enumerable
  end
end

Leads to: import_methods': Can't import method: Enumerable#drop (ArgumentError)
Which, grepping through code, seems to be raised here but I am not versed enough in Ruby internals to debug further.

An attempt to import_methods Comparable leads to the same problem, BTW: Can't import method: Comparable#between?

Am I missing something crucial about import_method behavior?

Updated by Eregon (Benoit Daloze) over 2 years ago

  • Assignee set to shugo (Shugo Maeda)

It means you can't import methods defined in C, only methods defined with Ruby code.
Methods need to be defined in Ruby code to be affected by refinements (e.g. other refinements in that refine block or under M).
So for example this wouldn't work if you define each inside refine String do since those C methods wouldn't know how to find each with refinements (e.g., they use rb_funcall which doesn't know about refinements).
(it would work on Ruby implementations where Enumerable is defined in Ruby code, interestingly)

@shugo (Shugo Maeda) WDYT?

I think we should improve the error message, like:
Can't import method which is not defined with Ruby code: Comparable#between?

Updated by zverok (Victor Shepelev) over 2 years ago

Yeah, at least the message should be clearer.

I didn't realize that import_methods is a make-believe feature, not really integrated with the interpreter/object model.

Are there any plans to integrate it more tightly, with refinements being "visible" to C code?..

Updated by shugo (Shugo Maeda) over 2 years ago

  • Status changed from Open to Assigned

Eregon (Benoit Daloze) wrote in #note-1:

It means you can't import methods defined in C, only methods defined with Ruby code.
Methods need to be defined in Ruby code to be affected by refinements (e.g. other refinements in that refine block or under M).
So for example this wouldn't work if you define each inside refine String do since those C methods wouldn't know how to find each with refinements (e.g., they use rb_funcall which doesn't know about refinements).
(it would work on Ruby implementations where Enumerable is defined in Ruby code, interestingly)

@shugo (Shugo Maeda) WDYT?

Yes, it's an implementation issue.

I think we should improve the error message, like:
Can't import method which is not defined with Ruby code: Comparable#between?

Thank you. I'll fix the error message.

zverok (Victor Shepelev) wrote in #note-2:

Yeah, at least the message should be clearer.

I didn't realize that import_methods is a make-believe feature, not really integrated with the interpreter/object model.

Are there any plans to integrate it more tightly, with refinements being "visible" to C code?..

Currently I have no plan and afraid that it may bring another implementation difficulty.

Actions #4

Updated by shugo (Shugo Maeda) over 2 years ago

  • Status changed from Assigned to Closed

Applied in changeset git|c2192cb985c10c90ba5e4d64652f79f89afff983.


Clarify the error message when trying to import C methods [Bug #18385]

Updated by Eregon (Benoit Daloze) over 2 years ago

zverok (Victor Shepelev) wrote in #note-2:

I didn't realize that import_methods is a make-believe feature, not really integrated with the interpreter/object model.

Not sure what you mean by that, in my POV it is integrated and it has the effect to "copy" methods from a module to another module or to a refinement, so that refinements can apply as if they were defined there lexically.

C extension-defined methods never supported refinements and likely never will (there is no lexical context for a call there).

Updated by zverok (Victor Shepelev) over 2 years ago

Eregon (Benoit Daloze) wrote in #note-5:

zverok (Victor Shepelev) wrote in #note-2:

I didn't realize that import_methods is a make-believe feature, not really integrated with the interpreter/object model.

Not sure what you mean by that, in my POV it is integrated and it has the effect to "copy" methods from a module to another module or to a refinement, so that refinements can apply as if they were defined there lexically.

C extension-defined methods never supported refinements and likely never will (there is no lexical context for a call there).

Well... We can look from many different angles at the problem.

From one side, I can understand the technical reasons how you explain them.

On another side, I still "intuitively" expect refinements to be a hygienic replacement for core_ext.rb, and every time this expectation fails, I am a bit frustrated. I mean, I might do that, right?.. (Save for the sanity of this approach discussion, but imagine I hack a few scripts for quick binary data investigation and decided in those scripts it would be the most convenient):

class String
  alias each each_byte
  include Enumerable
end

[1, 2, 3].chain('123').zip('abcdef')
# => [[1, 97], [2, 98], [3, 99], [49, 100], [50, 101], [51, 102]]

...but I can't for the love of all gods achieve the same with refinements—which would be the very first guess if you do something so violent you need in exactly one algorithm.

That's why I call import_methods a "make-believe" feature: unlike include/extend (which didn't work in refinements) it makes the border between methods defined in Ruby and methods defined in C visible, and thus look like something loosely glued on top of the object model.

It can be "technically explained", but it doesn't become "natural" after the explanation.

But honestly, I feel like the whole mental model of refinements is doomed from the start, the limitation of the "additional" functionality to text file borders is unusable in a dynamic language.

(As an aside note, it is funny how "extension methods" became in fashion in all the languages that criticized Ruby for being "too unreliable" for being able to extend core classes—and at the same time, in the Ruby community, it became a taboo.)

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0