Author: Shugo Maeda Status: Open Priority: Normal Assignee: Category: core Target version: 1.9.x
=begin As I said at RubyConf 2010, I'd like to propose a new features called "Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't support local rebinding as mentioned later. In this sense, Refinements might be more similar to selector namespaces, but I'm not sure because I have never seen any implementation of selector namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for class extensions. Such class extensions are called refinements. For example, the following module refines Fixnum.
module MathN refine Fixnum do def /(other) quo(other) end end end
Module#refine(klass) takes one argument, which is a class to be extended. Module#refine also takes a block, where additional or overriding methods of klass can be defined. In this example, MathN refines Fixnum so that 1 / 2 returns a rational number (1/2) instead of an integer 0.
This refinement can be enabled by the method using.
class Foo using MathN
def foo p 1 / 2 end end
f = Foo.new f.foo #=> (1/2) p 1 / 2
In this example, the refinement in MathN is enabled in the definition of Foo. The effective scope of the refinement is the innermost class, module, or method where using is called; however the refinement is not enabled before the call of using. If there is no such class, module, or method, then the effective scope is the file where using is called. Note that refinements are pseudo-lexically scoped. For example, foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo def bar puts "Foo#bar" end
def baz bar end end
module FooExt refine Foo do def bar puts "FooExt#bar" end end end
Refinements are also enabled in reopened definitions of classes using refinements and definitions of their subclasses, so they are *pseudo*-lexically scoped.
class Foo using MathN end
class Foo # MathN is enabled in a reopened definition. p 1 / 2 #=> (1/2) end
class Bar < Foo # MathN is enabled in a subclass definition. p 1 / 2 #=> (1/2) end
If a module or class is using refinements, they are enabled in module_eval, class_eval, and instance_eval if the receiver is the class or module, or an instance of the class.
module A using MathN end class B using MathN end MathN.module_eval do p 1 / 2 #=> (1/2) end A.module_eval do p 1 / 2 #=> (1/2) end B.class_eval do p 1 / 2 #=> (1/2) end B.new.instance_eval do p 1 / 2 #=> (1/2) end
Besides refinements, I'd like to propose new behavior of nested methods. Currently, the scope of a nested method is not closed in the outer method.
def foo def bar puts "bar" end bar end foo #=> bar bar #=> bar
In Ruby, there are no functions, but only methods. So there are no right places where nested methods are defined. However, if refinements are introduced, a refinement enabled only in the outer method would be the right place. For example, the above code is almost equivalent to the following code:
def foo klass = self.class m = Module.new { refine klass do def bar puts "bar" end end } using m bar end foo #=> bar bar #=> NoMethodError
The attached patch is based on SVN trunk r29837. =end
Author: shugo Status: Open Priority: Normal Assignee: shugo Category: core Target version: 2.0.0
=begin As I said at RubyConf 2010, I'd like to propose a new features called "Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't support local rebinding as mentioned later. In this sense, Refinements might be more similar to selector namespaces, but I'm not sure because I have never seen any implementation of selector namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for class extensions. Such class extensions are called refinements. For example, the following module refines Fixnum.
module MathN refine Fixnum do def /(other) quo(other) end end end
Module#refine(klass) takes one argument, which is a class to be extended. Module#refine also takes a block, where additional or overriding methods of klass can be defined. In this example, MathN refines Fixnum so that 1 / 2 returns a rational number (1/2) instead of an integer 0.
This refinement can be enabled by the method using.
class Foo using MathN
def foo p 1 / 2 end end
f = Foo.new f.foo #=> (1/2) p 1 / 2
In this example, the refinement in MathN is enabled in the definition of Foo. The effective scope of the refinement is the innermost class, module, or method where using is called; however the refinement is not enabled before the call of using. If there is no such class, module, or method, then the effective scope is the file where using is called. Note that refinements are pseudo-lexically scoped. For example, foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo def bar puts "Foo#bar" end
def baz bar end end
module FooExt refine Foo do def bar puts "FooExt#bar" end end end
Refinements are also enabled in reopened definitions of classes using refinements and definitions of their subclasses, so they are *pseudo*-lexically scoped.
class Foo using MathN end
class Foo # MathN is enabled in a reopened definition. p 1 / 2 #=> (1/2) end
class Bar < Foo # MathN is enabled in a subclass definition. p 1 / 2 #=> (1/2) end
If a module or class is using refinements, they are enabled in module_eval, class_eval, and instance_eval if the receiver is the class or module, or an instance of the class.
module A using MathN end class B using MathN end MathN.module_eval do p 1 / 2 #=> (1/2) end A.module_eval do p 1 / 2 #=> (1/2) end B.class_eval do p 1 / 2 #=> (1/2) end B.new.instance_eval do p 1 / 2 #=> (1/2) end
Besides refinements, I'd like to propose new behavior of nested methods. Currently, the scope of a nested method is not closed in the outer method.
def foo def bar puts "bar" end bar end foo #=> bar bar #=> bar
In Ruby, there are no functions, but only methods. So there are no right places where nested methods are defined. However, if refinements are introduced, a refinement enabled only in the outer method would be the right place. For example, the above code is almost equivalent to the following code:
def foo klass = self.class m = Module.new { refine klass do def bar puts "bar" end end } using m bar end foo #=> bar bar #=> NoMethodError
The attached patch is based on SVN trunk r29837. =end
Issue #4085 has been updated by jaffa62 (jaffa wify).
Data movement is typically from one place in memory to another. Sometimes it involves moving data between memory and registers which enable high speed data access in the CPU. Thanks.
Regards,
http://www.personalstatementwriters.com/services/
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
Issue #4085 has been updated by shugo (Shugo Maeda).
shugo (Shugo Maeda) wrote:
> Matz said the only problem is performance before, so I assign this issue to ko1.
I've committed refinements in r36596 with Matz's permission. However,
it's just an experimental feature, and may be reverted before the release of 2.0.
Please try it, and give us feedback.
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
Issue #4085 has been updated by Eregon (Benoit Daloze).
trans (Thomas Sawyer) wrote:
> =begin
> module MyApp
> include Facets
> end
> Would that work?
> =end
Yes, except you need to use `using` and not `include` in `module MyApp`.
----------------------------------------
Feature #4085: Refinements and nested methods
https://bugs.ruby-lang.org/issues/4085#change-28792
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
Issue #4085 has been updated by shugo (Shugo Maeda).
Assignee changed from shugo (Shugo Maeda) to matz (Yukihiro Matsumoto)
ko1 (Koichi Sasada) wrote:
> Any problem now?
I like the current behavior of Refinements, so please give me feedback if you don't like it.
Some objections to Refinements are summarized below:
* Refinements are too complex.
* Refinements should support local rebinding.
* using should be a keyword.
* refine should be a keyword.
Matz should decide whether Refinements should be included in Ruby 2.0, but I'm not sure whether he has tried Refinements or not.
----------------------------------------
Feature #4085: Refinements and nested methods
https://bugs.ruby-lang.org/issues/4085#change-31846
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
Issue #4085 has been updated by headius (Charles Nutter).
I would like to request time to implement refinements as they stand today in JRuby.
We have not had much time to look into how refinements will affect the way we optimize Ruby code, structure class hierarchies, and so on. The impact could be severe, or it could be minimal. I am worried because I don't know, and because up until today (Matz's keynote) I thought they were still questionable for 2.0.0.
So...we will implement refinements in JRuby (possibly on a branch) as soon as possible...within the next month for sure. I hope if we run into issues with the currently-specified behavior there will be time to make changes.
----------------------------------------
Feature #4085: Refinements and nested methods
https://bugs.ruby-lang.org/issues/4085#change-32195
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
Issue #4085 has been updated by shugo (Shugo Maeda).
headius (Charles Nutter) wrote:
> I would like to request time to implement refinements as they stand today in JRuby.
> We have not had much time to look into how refinements will affect the way we optimize Ruby code, structure class hierarchies, and so on. The impact could be severe, or it could be minimal. I am worried because I don't know, and because up until today (Matz's keynote) I thought they were still questionable for 2.0.0.
> So...we will implement refinements in JRuby (possibly on a branch) as soon as possible...within the next month for sure. I hope if we run into issues with the currently-specified behavior there will be time to make changes.
Thanks for your consideration of Refinements.
Please inform me if the current behavior of Refinements is hard to implement in JRuby.
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
Issue #4085 has been updated by headius (Charles Nutter).
Ok, early notes from writing up specs and starting to explore an implementation for JRuby.
* Refinements in modules and class hierarchies does not seem like a problem to me yet.
* Refinements are "used" in temporal order...methods added before "using" won't see refinements, refinements added after "using" won't be applied. I think this is a good thing, since it allows us to have a one-shot flag for refinements on methods at definition time.
* I notice 2.0.0 does not appear to have a performance impact from refinements in a simple case. No idea how refinements interact with cache invalidation yet.
Now, the bad:
* Months ago when the original proposal came out, I expressed my concern about refinements applying to module_eval and friends. I still strongly object to this behavior.
The problems I enumerated then still apply. Because module/class_eval can take any arbitrary block, including blocks of code from distant locations that do not know anything about used refinements, all calls in all blocks would need to check for refinements every time. This is the simple performance/optimization concern. MRI's invalidation mechanisms are simple enough that it may not affect MRI right now...but if invalidation mechanisms like those in JRuby are ever desired in MRI, I don't think this feature can exist.
It is also a GROSS security issue on the scale of block-as-binding. If a library can force code within a block to make completely different calls than the author intended, you're going to cause terrible confusion. Say I write some code in a block and pass it to a badly-written or malicious receiver. That receiver module_eval's my block in a refined scope, changing one or more of the calls I wrote. Suddenly my code, tested in my environment, can behave completely differently just by being passed as a block. If there are errors, they'll be errors reporting my code calling some other method I never intended.
Look at this code and tell me what method it calls:
def my_code(string)
your_code { string.to_i(16) }
end
The answer is that you can't tell me what method it is calling because the your_code method can basically force it to call anything.
This is actually *worse* than monkey patching, because after the call to your_code has completed, I have no evidence that a refinement was active. I need to go spelunking in your_code to figure out why my code didn't behave the way it should.
This is dynamic application of refinements, which has been hotly debated and which I *thought* was supposed to be removed. I assume it has been left in because it is required to apply refinements "magically" to all-block code like rspec. I do not see this as an excuse to introduce such an unpredictable feature.
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
Issue #4085 has been updated by headius (Charles Nutter).
Adding a couple additional positive notes:
* For now, I don't see a reason for using and refine to be keywords.
using and refine basically just add some additional state to modules and methods.
For refine:
* add to the module a mapping from refined class/module to the refinements that should be applied
* mark the containing module as having refinements active
For using:
* copy to the target module all currently active module => refinement mappings.
* tag methods defined after the using call to indicate that they should use refinement lookup
I think this is all doable without major alteration of most VMs caching, jitting, optimization mechanisms.
module_eval and class_eval are a different issue. There's no indication ahead of time that calls within those scopes need to use refinements, so you have to check constantly and enlist in refinement lookup unconditionally.
----------------------------------------
Feature #4085: Refinements and nested methods
https://bugs.ruby-lang.org/issues/4085#change-32245
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
Issue #4085 has been updated by shugo (Shugo Maeda).
headius (Charles Nutter) wrote:
> Ok, early notes from writing up specs and starting to explore an implementation for JRuby.
Thanks.
> * Refinements in modules and class hierarchies does not seem like a problem to me yet.
> * Refinements are "used" in temporal order...methods added before "using" won't see refinements, refinements added after "using" won't be applied. I think this is a good thing, since it allows us to have a one-shot flag for refinements on methods at definition time.
The current behavior is mainly for an implementation reason, but Matz and ko1 seem not to like it:(
> * Months ago when the original proposal came out, I expressed my concern about refinements applying to module_eval and friends. I still strongly object to this behavior.
I also wonder whether module_eval with blocks should be affected by refinements or not, but I think module_eval with strings (e.g., M.module_eval("C.new.foo")) has no problem, right?
> This is dynamic application of refinements, which has been hotly debated and which I *thought* was supposed to be removed. I assume it has been left in because it is required to apply refinements "magically" to all-block code like rspec. I do not see this as an excuse to introduce such an unpredictable feature.
instance_eval and module_eval themselves have the same problem because they change self "magically".
At first, I thought they are evil, but they are popular now.
I'd like to ask Matz's opinion.
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
On Fri, Nov 2, 2012 at 7:12 PM, shugo (Shugo Maeda)
<redm...@ruby-lang.org> wrote:
> headius (Charles Nutter) wrote:
> > * Refinements in modules and class hierarchies does not seem like a problem to me yet.
> > * Refinements are "used" in temporal order...methods added before "using" won't see refinements, refinements added after "using" won't be applied. I think this is a good thing, since it allows us to have a one-shot flag for refinements on methods at definition time.
> The current behavior is mainly for an implementation reason, but Matz and ko1 seem not to like it:(
I commented on ko1's bug. I see using a bit like visibility changes,
only affecting methods defined later on.
I understand the implementation reason as well...in order to limit the
damage of refinements, your impl flags methods as having refinements
active. For optimization purposes, that means we know at definition
time whether we need to handle refinements at all.
> > * Months ago when the original proposal came out, I expressed my concern about refinements applying to module_eval and friends. I still strongly object to this behavior.
> I also wonder whether module_eval with blocks should be affected by refinements or not, but I think module_eval with strings (e.g., M.module_eval("C.new.foo")) has no problem, right?
String eval would not be a problem, that is correct. We would be able
to see at eval time that the target module has refinements active.
> > This is dynamic application of refinements, which has been hotly debated and which I *thought* was supposed to be removed. I assume it has been left in because it is required to apply refinements "magically" to all-block code like rspec. I do not see this as an excuse to introduce such an unpredictable feature.
> instance_eval and module_eval themselves have the same problem because they change self "magically".
> At first, I thought they are evil, but they are popular now.
> I'd like to ask Matz's opinion.
Yes, module_eval, class_eval, and instance_eval are all problematic
because of the self changing, but module_eval and class_eval are
especially bad if they force refinements on code that doesn't know
about them.
I am starting to see some intractable problems with refinements, unfortunately.
In order to avoid having every call in the system check for
refinements, they are applied in evaluation order. However, this means
that the load order of scripts can now completely change which methods
get called. For example...
a.rb:
class Foo
def go(obj)
obj.something
end
end
b.rb:
class Foo
using Baz # refines the "something" call
end
If the files are loaded in the order a, b, no refinements are applied
to the something call. If b is loaded before a, refinements are
applied to the something call. No other features in Ruby are so
sensitive to load order (other than those that introspect classes and
methods, obviously).
The alternative is to have refinements not be applied temporally.
However this means every call in the system needs to check for
refinements every time. Given the complexity of method lookup in Ruby
today, adding refinements to that process seems like a terrible idea.
In order to cache a method call in the presence of refinements, we
need to track all of the following:
1. whether any refinements are active
2. whether there are refinements that affect the class of the target
of the method call
3. whether refinements that affect the target class redefine the target method
If any of these change at any time, we need to invalidate the cache.
This is on top of all the information we need to do to cache methods
normally.
At this point I would not vote for refinements to be included in Ruby
2.0. I feel like there are far too many edge cases and implementation
concerns.
I could get behind refinements if using were a keyword (so we could
tell at parse time refinements would be active) and purely lexical.
The following features of the current implementation would have to be
removed:
* refinements cascading down class hierarchies
* refinements affecting code in module_eval'ed blocks
If using became a keyword and purely lexical, the following examples
would be fine:
rails_thing.rb:
class Foo
using ActiveRecord::SomeExt
...
end
rspec_thing.rb:
using RSpec
describe 'Refinements' do
it 'should be purely lexical' do
...
If refinements can affect code outside the lexical scope where they
are activated, I believe it will be confusing, potentially dangerous,
very hard to debug, and potentially difficult or impossible to
implement without slowing all of Ruby down.
On Sat, Nov 3, 2012 at 10:38 AM, Charles Oliver Nutter
<head...@headius.com> wrote:
> On Fri, Nov 2, 2012 at 7:12 PM, shugo (Shugo Maeda)
> <redm...@ruby-lang.org> wrote:
>> headius (Charles Nutter) wrote:
>> > * Refinements in modules and class hierarchies does not seem like a problem to me yet.
>> > * Refinements are "used" in temporal order...methods added before "using" won't see refinements, refinements added after "using" won't be applied. I think this is a good thing, since it allows us to have a one-shot flag for refinements on methods at definition time.
>> The current behavior is mainly for an implementation reason, but Matz and ko1 seem not to like it:(
> I commented on ko1's bug. I see using a bit like visibility changes,
> only affecting methods defined later on.
> I understand the implementation reason as well...in order to limit the
> damage of refinements, your impl flags methods as having refinements
> active. For optimization purposes, that means we know at definition
> time whether we need to handle refinements at all.
>> > * Months ago when the original proposal came out, I expressed my concern about refinements applying to module_eval and friends. I still strongly object to this behavior.
>> I also wonder whether module_eval with blocks should be affected by refinements or not, but I think module_eval with strings (e.g., M.module_eval("C.new.foo")) has no problem, right?
> String eval would not be a problem, that is correct. We would be able
> to see at eval time that the target module has refinements active.
>> > This is dynamic application of refinements, which has been hotly debated and which I *thought* was supposed to be removed. I assume it has been left in because it is required to apply refinements "magically" to all-block code like rspec. I do not see this as an excuse to introduce such an unpredictable feature.
>> instance_eval and module_eval themselves have the same problem because they change self "magically".
>> At first, I thought they are evil, but they are popular now.
>> I'd like to ask Matz's opinion.
> Yes, module_eval, class_eval, and instance_eval are all problematic
> because of the self changing, but module_eval and class_eval are
> especially bad if they force refinements on code that doesn't know
> about them.
> I am starting to see some intractable problems with refinements, unfortunately.
> In order to avoid having every call in the system check for
> refinements, they are applied in evaluation order. However, this means
> that the load order of scripts can now completely change which methods
> get called. For example...
> a.rb:
> class Foo
> def go(obj)
> obj.something
> end
> end
> b.rb:
> class Foo
> using Baz # refines the "something" call
> end
> If the files are loaded in the order a, b, no refinements are applied
> to the something call. If b is loaded before a, refinements are
> applied to the something call. No other features in Ruby are so
> sensitive to load order (other than those that introspect classes and
> methods, obviously).
> The alternative is to have refinements not be applied temporally.
> However this means every call in the system needs to check for
> refinements every time. Given the complexity of method lookup in Ruby
> today, adding refinements to that process seems like a terrible idea.
> In order to cache a method call in the presence of refinements, we
> need to track all of the following:
> 1. whether any refinements are active
> 2. whether there are refinements that affect the class of the target
> of the method call
> 3. whether refinements that affect the target class redefine the target method
> If any of these change at any time, we need to invalidate the cache.
> This is on top of all the information we need to do to cache methods
> normally.
> At this point I would not vote for refinements to be included in Ruby
> 2.0. I feel like there are far too many edge cases and implementation
> concerns.
Issue #4085 has been updated by headius (Charles Nutter).
Discussed refinements a bit with Matz + ko1 plus a_matsuda and others at lunch...here's summary.
The using method currently touches cref, making it largely scoped like constants. If refinement lookup at a call site proceeds the same way, it would simplify things in my head quite a bit.
Benefits to having refinement lookup follow cref:
* No frame field is necessary
* Easier-to-understand behavior, since the lookup would mimic constant lookup (lexical then hierarchical)
There are down sides:
* module_eval cases would not be possible, since like constant lookup refinements cannot be injected into a scope after the fact
* It is not purely lexical, as I had hoped. However, I recognize that having to "using" in every scope where you want refinements to be active would be painful.
* It may need a global invalidation guard, like constants. It may not, though, since refinements are applied only once, at definition time; so after caching once we may have everything we need for future invalidation.
One concern of mine was avoiding refinement checks at all call sites. With cref-based "using" there's no way to determine at parse time which methods might need refinements. We can determine it at definition time, but the AST is already parsed at that point, so we'd have to rewrite it to have "refined calls" instead of normal calls, or something similar. This also impacts JRuby's ahead-of-time compilation support...we do not have the luxury of running the target code for precompilation, so we can't see if there are refinements active.
For normal runtime jitted code, rewriting the AST or adding a "refined" flag to call nodes may be feasible. Calls can then use a refined call site only in the cases where refinements are active.
For AOT mode, I think the best I can do is to have a flag on the call sites to indicate if refinements are active. If there's no refinements for the first call, there will be no refinements for any future calls, and we can turn that logic off. It would still require that boolean check every time...I don't see a way to eliminate that. (Side note: on invokedynamic, that boolean check would end up free, so it may not be a huge deal long term).
I will attempt to prototype pure cref-based refinement lookup over the next week.
----------------------------------------
Feature #4085: Refinements and nested methods
https://bugs.ruby-lang.org/issues/4085#change-32309
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
> Issue #4085 has been updated by headius (Charles Nutter).
> Discussed refinements a bit with Matz + ko1 plus a_matsuda and others at lunch...here's summary.
> The using method currently touches cref, making it largely scoped like constants. If refinement lookup at a call site proceeds the same way, it would simplify things in my head quite a bit.
> Benefits to having refinement lookup follow cref:
> * No frame field is necessary
> * Easier-to-understand behavior, since the lookup would mimic constant lookup (lexical then hierarchical)
> There are down sides:
> * module_eval cases would not be possible, since like constant lookup refinements cannot be injected into a scope after the fact
> * It is not purely lexical, as I had hoped. However, I recognize that having to "using" in every scope where you want refinements to be active would be painful.
> * It may need a global invalidation guard, like constants. It may not, though, since refinements are applied only once, at definition time; so after caching once we may have everything we need for future invalidation.
> One concern of mine was avoiding refinement checks at all call sites. With cref-based "using" there's no way to determine at parse time which methods might need refinements. We can determine it at definition time, but the AST is already parsed at that point, so we'd have to rewrite it to have "refined calls" instead of normal calls, or something similar. This also impacts JRuby's ahead-of-time compilation support...we do not have the luxury of running the target code for precompilation, so we can't see if there are refinements active.
> For normal runtime jitted code, rewriting the AST or adding a "refined" flag to call nodes may be feasible. Calls can then use a refined call site only in the cases where refinements are active.
> For AOT mode, I think the best I can do is to have a flag on the call sites to indicate if refinements are active. If there's no refinements for the first call, there will be no refinements for any future calls, and we can turn that logic off. It would still require that boolean check every time...I don't see a way to eliminate that. (Side note: on invokedynamic, that boolean check would end up free, so it may not be a huge deal long term).
> I will attempt to prototype pure cref-based refinement lookup over the next week.
> ----------------------------------------
> Feature #4085: Refinements and nested methods
> https://bugs.ruby-lang.org/issues/4085#change-32309
> =begin
> As I said at RubyConf 2010, I'd like to propose a new features called
> "Refinements."
> Refinements are similar to Classboxes. However, Refinements doesn't
> support local rebinding as mentioned later. In this sense,
> Refinements might be more similar to selector namespaces, but I'm not
> sure because I have never seen any implementation of selector
> namespaces.
> In Refinements, a Ruby module is used as a namespace (or classbox) for
> class extensions. Such class extensions are called refinements. For
> example, the following module refines Fixnum.
> module MathN
> refine Fixnum do
> def /(other) quo(other) end
> end
> end
> Module#refine(klass) takes one argument, which is a class to be
> extended. Module#refine also takes a block, where additional or
> overriding methods of klass can be defined. In this example, MathN
> refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
> of an integer 0.
> This refinement can be enabled by the method using.
> class Foo
> using MathN
> def foo
> p 1 / 2
> end
> end
> f = Foo.new
> f.foo #=> (1/2)
> p 1 / 2
> In this example, the refinement in MathN is enabled in the definition
> of Foo. The effective scope of the refinement is the innermost class,
> module, or method where using is called; however the refinement is not
> enabled before the call of using. If there is no such class, module,
> or method, then the effective scope is the file where using is called.
> Note that refinements are pseudo-lexically scoped. For example,
> foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
> class Foo
> def bar
> puts "Foo#bar"
> end
> def baz
> bar
> end
> end
> module FooExt
> refine Foo do
> def bar
> puts "FooExt#bar"
> end
> end
> end
> Refinements are also enabled in reopened definitions of classes using
> refinements and definitions of their subclasses, so they are
> *pseudo*-lexically scoped.
> class Foo
> using MathN
> end
> class Foo
> # MathN is enabled in a reopened definition.
> p 1 / 2 #=> (1/2)
> end
> class Bar < Foo
> # MathN is enabled in a subclass definition.
> p 1 / 2 #=> (1/2)
> end
> If a module or class is using refinements, they are enabled in
> module_eval, class_eval, and instance_eval if the receiver is the
> class or module, or an instance of the class.
> module A
> using MathN
> end
> class B
> using MathN
> end
> MathN.module_eval do
> p 1 / 2 #=> (1/2)
> end
> A.module_eval do
> p 1 / 2 #=> (1/2)
> end
> B.class_eval do
> p 1 / 2 #=> (1/2)
> end
> B.new.instance_eval do
> p 1 / 2 #=> (1/2)
> end
> Besides refinements, I'd like to propose new behavior of nested methods.
> Currently, the scope of a nested method is not closed in the outer method.
> def foo
> def bar
> puts "bar"
> end
> bar
> end
> foo #=> bar
> bar #=> bar
> In Ruby, there are no functions, but only methods. So there are no
> right places where nested methods are defined. However, if
> refinements are introduced, a refinement enabled only in the outer
> method would be the right place. For example, the above code is
> almost equivalent to the following code:
> def foo
> klass = self.class
> m = Module.new {
> refine klass do
> def bar
> puts "bar"
> end
> end
> }
> using m
> bar
> end
> foo #=> bar
> bar #=> NoMethodError
> The attached patch is based on SVN trunk r29837.
> =end
Playing with refinements after talking with Charlie, I found
refinements are not very much attractive feature without module_eval.
I think I do understand the down sides Charlie described.
And I'm sure people will abuse this refinements + module_eval
technique if they are allowed to, because it just looks cool.
So, I guess the point is whether to allow users to write code like this or not;
module A
refine Fixnum do
def +(o); self * o; end
end
end
class C
def foo(&b)
Module.new { using A }.module_eval &b
end
end
C.new.foo { p 2 + 3 }
#=> 6
My personal opinion is, still, as a library / framework author, I'm
sort of anticipating to see such future that people are abusing this.
People may find good practices to control the power somehow, then it
might definitely push the DSL culture up to the absolute next level,
which must be totally exciting.
On Sat, Nov 3, 2012 at 2:57 PM, SASADA Koichi <k...@atdot.net> wrote:
> I have another implementation idea, using "prepend".
> I also try it next week.
> (I can't explain this idea in English, so I will write code).
>> Issue #4085 has been updated by headius (Charles Nutter).
>> Discussed refinements a bit with Matz + ko1 plus a_matsuda and others at lunch...here's summary.
>> The using method currently touches cref, making it largely scoped like constants. If refinement lookup at a call site proceeds the same way, it would simplify things in my head quite a bit.
>> Benefits to having refinement lookup follow cref:
>> * No frame field is necessary
>> * Easier-to-understand behavior, since the lookup would mimic constant lookup (lexical then hierarchical)
>> There are down sides:
>> * module_eval cases would not be possible, since like constant lookup refinements cannot be injected into a scope after the fact
>> * It is not purely lexical, as I had hoped. However, I recognize that having to "using" in every scope where you want refinements to be active would be painful.
>> * It may need a global invalidation guard, like constants. It may not, though, since refinements are applied only once, at definition time; so after caching once we may have everything we need for future invalidation.
>> One concern of mine was avoiding refinement checks at all call sites. With cref-based "using" there's no way to determine at parse time which methods might need refinements. We can determine it at definition time, but the AST is already parsed at that point, so we'd have to rewrite it to have "refined calls" instead of normal calls, or something similar. This also impacts JRuby's ahead-of-time compilation support...we do not have the luxury of running the target code for precompilation, so we can't see if there are refinements active.
>> For normal runtime jitted code, rewriting the AST or adding a "refined" flag to call nodes may be feasible. Calls can then use a refined call site only in the cases where refinements are active.
>> For AOT mode, I think the best I can do is to have a flag on the call sites to indicate if refinements are active. If there's no refinements for the first call, there will be no refinements for any future calls, and we can turn that logic off. It would still require that boolean check every time...I don't see a way to eliminate that. (Side note: on invokedynamic, that boolean check would end up free, so it may not be a huge deal long term).
>> I will attempt to prototype pure cref-based refinement lookup over the next week.
>> ----------------------------------------
>> Feature #4085: Refinements and nested methods
>> https://bugs.ruby-lang.org/issues/4085#change-32309
>> =begin
>> As I said at RubyConf 2010, I'd like to propose a new features called
>> "Refinements."
>> Refinements are similar to Classboxes. However, Refinements doesn't
>> support local rebinding as mentioned later. In this sense,
>> Refinements might be more similar to selector namespaces, but I'm not
>> sure because I have never seen any implementation of selector
>> namespaces.
>> In Refinements, a Ruby module is used as a namespace (or classbox) for
>> class extensions. Such class extensions are called refinements. For
>> example, the following module refines Fixnum.
>> module MathN
>> refine Fixnum do
>> def /(other) quo(other) end
>> end
>> end
>> Module#refine(klass) takes one argument, which is a class to be
>> extended. Module#refine also takes a block, where additional or
>> overriding methods of klass can be defined. In this example, MathN
>> refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
>> of an integer 0.
>> This refinement can be enabled by the method using.
>> class Foo
>> using MathN
>> def foo
>> p 1 / 2
>> end
>> end
>> f = Foo.new
>> f.foo #=> (1/2)
>> p 1 / 2
>> In this example, the refinement in MathN is enabled in the definition
>> of Foo. The effective scope of the refinement is the innermost class,
>> module, or method where using is called; however the refinement is not
>> enabled before the call of using. If there is no such class, module,
>> or method, then the effective scope is the file where using is called.
>> Note that refinements are pseudo-lexically scoped. For example,
>> foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
>> class Foo
>> def bar
>> puts "Foo#bar"
>> end
>> def baz
>> bar
>> end
>> end
>> module FooExt
>> refine Foo do
>> def bar
>> puts "FooExt#bar"
>> end
>> end
>> end
>> Refinements are also enabled in reopened definitions of classes using
>> refinements and definitions of their subclasses, so they are
>> *pseudo*-lexically scoped.
>> class Foo
>> using MathN
>> end
>> class Foo
>> # MathN is enabled in a reopened definition.
>> p 1 / 2 #=> (1/2)
>> end
>> class Bar < Foo
>> # MathN is enabled in a subclass definition.
>> p 1 / 2 #=> (1/2)
>> end
>> If a module or class is using refinements, they are enabled in
>> module_eval, class_eval, and instance_eval if the receiver is the
>> class or module, or an instance of the class.
>> module A
>> using MathN
>> end
>> class B
>> using MathN
>> end
>> MathN.module_eval do
>> p 1 / 2 #=> (1/2)
>> end
>> A.module_eval do
>> p 1 / 2 #=> (1/2)
>> end
>> B.class_eval do
>> p 1 / 2 #=> (1/2)
>> end
>> B.new.instance_eval do
>> p 1 / 2 #=> (1/2)
>> end
>> Besides refinements, I'd like to propose new behavior of nested methods.
>> Currently, the scope of a nested method is not closed in the outer method.
>> def foo
>> def bar
>> puts "bar"
>> end
>> bar
>> end
>> foo #=> bar
>> bar #=> bar
>> In Ruby, there are no functions, but only methods. So there are no
>> right places where nested methods are defined. However, if
>> refinements are introduced, a refinement enabled only in the outer
>> method would be the right place. For example, the above code is
>> almost equivalent to the following code:
>> def foo
>> klass = self.class
>> m = Module.new {
>> refine klass do
>> def bar
>> puts "bar"
>> end
>> end
>> }
>> using m
>> bar
>> end
>> foo #=> bar
>> bar #=> NoMethodError
>> The attached patch is based on SVN trunk r29837.
>> =end
In message "Re: [ruby-core:48828] Re: [ruby-trunk - Feature #4085] Refinements and nested methods"
on Sun, 4 Nov 2012 08:42:11 +0900, Akira Matsuda <ron...@dio.jp> writes:
|
|Playing with refinements after talking with Charlie, I found
|refinements are not very much attractive feature without module_eval.
|I think I do understand the down sides Charlie described.
|And I'm sure people will abuse this refinements + module_eval
|technique if they are allowed to, because it just looks cool.
I agree. Even though there's chance to make program behavior
unpredictable, extending behavior in block with refinements would
enhance the possibility of expressiveness. ActiveRecord example is
one of them. As far as I understand, Charlie came up with an idea to
resolve refinements at the first method invocation. If the idea is a
right one, we can allow such cases.
But I am not sure allowing refinement application in blocks should be
done by module_eval or not. Generating anonymous module for every
block execution sound inefficient.
Issue #4085 has been updated by shugo (Shugo Maeda).
headius (Charles Nutter) wrote:
> Discussed refinements a bit with Matz + ko1 plus a_matsuda and others at lunch...here's summary.
Thanks for the summary.
The current implementation is cref-based because I came up with the idea inspired by pseudo lexical scope of constants. However, I admit that the current implementation has some issues, and don't stick to it.
I'd like to see your implementation and ko1's prepend-based implementation.
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
Issue #4085 has been updated by shugo (Shugo Maeda).
matz wrote:
> But I am not sure allowing refinement application in blocks should be
> done by module_eval or not. Generating anonymous module for every
> block execution sound inefficient.
Such an anonymous module may be reused in a_matsuda's cases, but method caching may be a worse problem. In the current implementation, using invalidates the global method cache and module_eval invokes using internally, which means that the global method cache is invalidated for each call of module_eval.
----------------------------------------
Feature #4085: Refinements and nested methods
https://bugs.ruby-lang.org/issues/4085#change-32357
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
On Sun, Nov 4, 2012 at 8:50 PM, shugo (Shugo Maeda)
<redm...@ruby-lang.org> wrote:
> Such an anonymous module may be reused in a_matsuda's cases, but method caching may be a worse problem. In the current implementation, using invalidates the global method cache and module_eval invokes using internally, which means that the global method cache is invalidated for each call of module_eval.
Unless an implementation can be found that doesn't do this, I don't
see how the module_eval feature can be supported. It seems totally
unreasonable to me that the global method cache would be invalidated
in this way.
Issue #4085 has been updated by headius (Charles Nutter).
shugo (Shugo Maeda) wrote:
> matz wrote:
> > But I am not sure allowing refinement application in blocks should be
> > done by module_eval or not. Generating anonymous module for every
> > block execution sound inefficient.
> Such an anonymous module may be reused in a_matsuda's cases, but method caching may be a worse problem. In the current implementation, using invalidates the global method cache and module_eval invokes using internally, which means that the global method cache is invalidated for each call of module_eval.
To me, this means the module_eval feature absolutely cannot be supported unless a new implementation can be found. No normal feature of Ruby should force full cache invalidation globally.
----------------------------------------
Feature #4085: Refinements and nested methods
https://bugs.ruby-lang.org/issues/4085#change-32365
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end
=begin
As I said at RubyConf 2010, I'd like to propose a new features called
"Refinements."
Refinements are similar to Classboxes. However, Refinements doesn't
support local rebinding as mentioned later. In this sense,
Refinements might be more similar to selector namespaces, but I'm not
sure because I have never seen any implementation of selector
namespaces.
In Refinements, a Ruby module is used as a namespace (or classbox) for
class extensions. Such class extensions are called refinements. For
example, the following module refines Fixnum.
module MathN
refine Fixnum do
def /(other) quo(other) end
end
end
Module#refine(klass) takes one argument, which is a class to be
extended. Module#refine also takes a block, where additional or
overriding methods of klass can be defined. In this example, MathN
refines Fixnum so that 1 / 2 returns a rational number (1/2) instead
of an integer 0.
This refinement can be enabled by the method using.
class Foo
using MathN
def foo
p 1 / 2
end
end
f = Foo.new
f.foo #=> (1/2)
p 1 / 2
In this example, the refinement in MathN is enabled in the definition
of Foo. The effective scope of the refinement is the innermost class,
module, or method where using is called; however the refinement is not
enabled before the call of using. If there is no such class, module,
or method, then the effective scope is the file where using is called.
Note that refinements are pseudo-lexically scoped. For example,
foo.baz prints not "FooExt#bar" but "Foo#bar" in the following code:
class Foo
def bar
puts "Foo#bar"
end
def baz
bar
end
end
module FooExt
refine Foo do
def bar
puts "FooExt#bar"
end
end
end
Refinements are also enabled in reopened definitions of classes using
refinements and definitions of their subclasses, so they are
*pseudo*-lexically scoped.
class Foo
using MathN
end
class Foo
# MathN is enabled in a reopened definition.
p 1 / 2 #=> (1/2)
end
class Bar < Foo
# MathN is enabled in a subclass definition.
p 1 / 2 #=> (1/2)
end
If a module or class is using refinements, they are enabled in
module_eval, class_eval, and instance_eval if the receiver is the
class or module, or an instance of the class.
module A
using MathN
end
class B
using MathN
end
MathN.module_eval do
p 1 / 2 #=> (1/2)
end
A.module_eval do
p 1 / 2 #=> (1/2)
end
B.class_eval do
p 1 / 2 #=> (1/2)
end
B.new.instance_eval do
p 1 / 2 #=> (1/2)
end
Besides refinements, I'd like to propose new behavior of nested methods.
Currently, the scope of a nested method is not closed in the outer method.
def foo
def bar
puts "bar"
end
bar
end
foo #=> bar
bar #=> bar
In Ruby, there are no functions, but only methods. So there are no
right places where nested methods are defined. However, if
refinements are introduced, a refinement enabled only in the outer
method would be the right place. For example, the above code is
almost equivalent to the following code:
def foo
klass = self.class
m = Module.new {
refine klass do
def bar
puts "bar"
end
end
}
using m
bar
end
foo #=> bar
bar #=> NoMethodError
The attached patch is based on SVN trunk r29837.
=end