Feature #8481

Module#using

Added by Shugo Maeda 11 months ago. Updated 10 months ago.

[ruby-core:55273]
Status:Closed
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:core
Target version:2.1.0

Description

As I said at RubyKaigi2013, refinements in Ruby 2.0 have a problem that it's impossible to use incompatible refinements in the same file.
And at RubyKaigi, I've proposed the new option using: of instanceeval, by which you can activate refinements in the specified module only in the given block.
See my presentation slides for details: http://shugo.net/tmp/refining
refinements.pdf

However, Matz doesn't like that idea for the following two reasons:

  1. It's difficult for users to expect what refinements are activated in a block.
  2. It's difficult for Ruby implementors to implement it efficiently.

So, I propose Module#using instead of the using: option of instance_eval.
Module#using had once been introduced into trunk, but it was removed from Ruby 2.0.
I'd like to make it simpler, as follows.

  1. Module#using activates refinements in a given module only in the current class or module definition.
  2. So Module#using is private and the receiver of Module#using should be self.
  3. The refinements never be activated in class or module definitions reopened later.
  4. The refinements never be inherited to subclasses.

That is, Module#using works lexically.

EXAMPLE 1

class Foo
using Ref1
# Refinements in Ref1 are activated only in the current definition of Foo.
end
class Bar
using Ref2
# Refinements in Ref2 are activated only in the current definition of Bar.
end

EXAMPLE 2

class Foo
using Ref1
# Refinements in Ref1 are activated only in the current definition of Foo.
end
class Foo
# Refinements in Ref1 are not activated here.
end

EXAMPLE 3

class Foo
using Ref1
# Refinements in Ref1 are activated only in the current definition of Foo.
end
class Bar < Foo
# Refinements in Ref1 are not activated here.
end

Any thoughts?

Associated revisions

Revision 41261
Added by Shugo Maeda 10 months ago

  • eval.c (mod_using): new method Module#using, which activates
    refinements of the specified module only in the current class or
    module definition. [Feature #8481]

  • test/ruby/test_refinement.rb: related test.

History

#1 Updated by Boris Stitnicky 11 months ago

Then, if it works lexically, it is not a function of Module, but of ... of ... Kernel? If it modified the module logically, it would be Module's concern. But like this, it is a concern of the interpreter, imao. Something like "private". I don't even know if "private" keyword is method :-)

#2 Updated by Yukihiro Matsumoto 11 months ago

As I already told you, I can accept (or even encourage) this change.
I am interested in how implementers of other Ruby.

Matz.

#3 Updated by Shugo Maeda 11 months ago

boris_stitnicky (Boris Stitnicky) wrote:

Then, if it works lexically, it is not a function of Module, but of ... of ... Kernel? If it modified the module logically, it would be Module's concern. But like this, it is a concern of the interpreter, imao. Something like "private". I don't even know if "private" keyword is method :-)

private is not a keyword. private at toplevel is the method main.private and private at module level is the method Module#private. Hence, it's reasonable to provide module-level using as Module#using.

#4 Updated by Charles Nutter 11 months ago

I do not currently have a problem with Module level #using, provided it is still lexical. The same mechanism for file-level #using would work here: if a "using" call is present in the code, we'll treat all calls in that scope as potentially refined (different call logic). Scopes without a #using call will not do refined dispatch.

A few other clarifications I think are important:

  • Since this is lexical, you can't send or send :using from any scope and expect it to work. It might work by accident on some implementations, but this is non-spec. Should it be specified that it explicitly does not work?
  • I assume we still do not have "magic" #send and #instance_method and friends, correct?

Regarding timeline for implementation in JRuby...

Because of the invasive nature of the changes required, we are not comfortable implementing it in the JRuby 1.7.x codebase. Therefore, we will probably not be able to start in earnest on a final implementation until after we branch 1.7. However, I would like to get a prototype implementation based on current 2.0 and upcoming 2.1 refinement features so we can work through issues sooner rather than later. I hope to do that this month...but hope is a complicated thing.

#5 Updated by Yukihiro Matsumoto 11 months ago

  • It's OK that send(:using) do not work
  • we will not provide magic send in the near future (no plan at all)

Matz.

#6 Updated by Shugo Maeda 11 months ago

headius (Charles Nutter) wrote:

A few other clarifications I think are important:

  • Since this is lexical, you can't send or send :using from any scope and expect it to work. It might work by accident on some implementations, but this is non-spec. Should it be specified that it explicitly does not work?
  • I assume we still do not have "magic" #send and #instance_method and friends, correct?

Agreed. Reflection API should not care refinements in Ruby 2.1.

Because of the invasive nature of the changes required, we are not comfortable implementing it in the JRuby 1.7.x codebase. Therefore, we will probably not be able to start in earnest on a final implementation until after we branch 1.7. However, I would like to get a prototype implementation based on current 2.0 and upcoming 2.1 refinement features so we can work through issues sooner rather than later. I hope to do that this month...but hope is a complicated thing.

I see. Thanks for your effort for refinements.

#7 Updated by Shugo Maeda 10 months ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r41261.
Shugo, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • eval.c (mod_using): new method Module#using, which activates
    refinements of the specified module only in the current class or
    module definition. [Feature #8481]

  • test/ruby/test_refinement.rb: related test.

Also available in: Atom PDF