[#50466] [ruby-trunk - Bug #7492][Open] Segmentation fault at DL::TestDL#test_call_double on x64 Windows 8 — "phasis68 (Heesob Park)" <phasis@...>
23 messages
2012/12/02
[#59083] [ruby-trunk - Bug #7492] Segmentation fault at DL::TestDL#test_call_double on x64 Windows 8
— "phasis68 (Heesob Park)" <phasis@...>
2013/12/13
[#50483] [IMPORTANT] 2.0.0 release plan — Yusuke Endoh <mame@...>
ALL COMMITTERS SHOULD READ THIS MAIL! コミッタはこのメール読んで!
5 messages
2012/12/02
[#50561] [ruby-trunk - Bug #7513][Open] TracePoint#enable/disable should not cause error — "ko1 (Koichi Sasada)" <redmine@...>
7 messages
2012/12/05
[#50575] [ruby-trunk - Feature #7517][Open] Fixnum::MIN,MAX — "matz (Yukihiro Matsumoto)" <matz@...>
20 messages
2012/12/05
[#50593] [ruby-trunk - Feature #7517] Fixnum::MIN,MAX
— "shyouhei (Shyouhei Urabe)" <shyouhei@...>
2012/12/05
[#50594] Re: [ruby-trunk - Feature #7517] Fixnum::MIN,MAX
— Charles Oliver Nutter <headius@...>
2012/12/05
On Wed, Dec 5, 2012 at 12:24 PM, shyouhei (Shyouhei Urabe)
[#50636] [ruby-trunk - Bug #7528][Open] CSV.== fails to check object type — "SteveW (Stephen Wattam)" <stephenwattam@...>
6 messages
2012/12/06
[#50645] [ruby-trunk - Bug #7530][Open] Concurrent loads fail with mutex errors — "headius (Charles Nutter)" <headius@...>
7 messages
2012/12/06
[#50660] [ruby-trunk - Feature #4085] Refinements and nested methods — "trans (Thomas Sawyer)" <transfire@...>
3 messages
2012/12/07
[#50699] Commit access for Yehuda Katz — Aaron Patterson <tenderlove@...>
Hi,
4 messages
2012/12/08
[#50923] Re: Commit access for Yehuda Katz
— Charles Oliver Nutter <headius@...>
2012/12/16
I will +1 this, unsure if it has happened already (it's "catch up on
[#50733] [ruby-trunk - Bug #7539][Open] Misleading error message "can't convert nil into string" — "connec (Chris Connelly)" <chris@...>
8 messages
2012/12/10
[#50755] Becoming a committer — Charlie Somerville <charlie@...>
Hi ruby-core,
21 messages
2012/12/11
[#50759] Re: Becoming a committer
— Yukihiro Matsumoto <matz@...>
2012/12/11
Hi,
[#50784] Re: Becoming a committer
— Charles Oliver Nutter <headius@...>
2012/12/11
It's really this easy? If so, I'll send over my public key today :)
[#50795] Re: Becoming a committer
— Yukihiro Matsumoto <matz@...>
2012/12/11
Hi,
[#50797] Re: Becoming a committer
— Charles Oliver Nutter <headius@...>
2012/12/11
I guess there's a few things I'd be interested in:
[#50809] Re: Becoming a committer
— SASADA Koichi <ko1@...>
2012/12/12
(2012/12/12 8:55), Charles Oliver Nutter wrote:
[#50815] Re: Becoming a committer
— Charles Oliver Nutter <headius@...>
2012/12/12
On Wed, Dec 12, 2012 at 12:04 AM, SASADA Koichi <[email protected]> wrote:
[#50816] Re: Becoming a committer
— "NARUSE, Yui" <naruse@...>
2012/12/12
2012/12/12 Charles Oliver Nutter <[email protected]>:
[#50817] Re: Becoming a committer
— Charles Oliver Nutter <headius@...>
2012/12/12
On Wed, Dec 12, 2012 at 2:59 AM, NARUSE, Yui <[email protected]> wrote:
[#50765] [ruby-trunk - Bug #7544][Open] Accented characters in IRB — cfabianski (Cédric FABIANSKI) <cfabianski@...>
6 messages
2012/12/11
[#50793] [ruby-trunk - Bug #7547][Open] Dir.mktmpdir('~something') tries to expand a profile directory — "jstanley0 (Jeremy Stanley)" <jeremy@...>
4 messages
2012/12/11
[#50810] [ruby-trunk - Feature #7549][Open] A Ruby Design Process — "brixen (Brian Ford)" <brixen@...>
34 messages
2012/12/12
[#50829] [ruby-trunk - Feature #7549] A Ruby Design Process
— "subwindow (Erik Peterson)" <erik@...>
2012/12/12
[#50837] [ruby-trunk - Feature #7549] A Ruby Design Process
— "subwindow (Erik Peterson)" <erik@...>
2012/12/12
[#50867] [ruby-trunk - Bug #7556][Assigned] test error on refinement — "usa (Usaku NAKAMURA)" <usa@...>
14 messages
2012/12/13
[#50900] [ruby-trunk - Bug #7564][Open] r38175 introduces incompatibility — "tenderlovemaking (Aaron Patterson)" <aaron@...>
14 messages
2012/12/14
[#50913] [ruby-trunk - Bug #7568][Open] Yaml fails to encode zero date string. — "anshul (Anshul Khandelwal)" <anshul@...>
5 messages
2012/12/15
[#50920] [ruby-trunk - Bug #7568][Assigned] Yaml fails to encode zero date string.
— "charliesome (Charlie Somerville)" <charlie@...>
2012/12/16
[#50988] Re: [ruby-trunk - Bug #7568][Assigned] Yaml fails to encode zero date string.
— Aaron Patterson <tenderlove@...>
2012/12/19
On Sun, Dec 16, 2012 at 12:53:14PM +0900, charliesome (Charlie Somerville) wrote:
[#51015] 1.9.3 patch level release — Zachary Scott <zachary@...>
I know unak-san was asking about a 1.9.3 patch level release, so I
8 messages
2012/12/20
[#51099] [ruby-trunk - Feature #7612][Open] Enumerators take a proc — "pedz (Perry Smith)" <pedz@...>
4 messages
2012/12/23
[ruby-core:50468] [ruby-trunk - Feature #4085] Refinements and nested methods
From:
"headius (Charles Nutter)" <headius@...>
Date:
2012-12-02 04:07:48 UTC
List:
ruby-core #50468
Issue #4085 has been updated by headius (Charles Nutter).
PROBLEM: reflection from within a refined scope
Several folks have stated they believe reflection from within a refined scope should reflect the refinements. I do not agree, based on a definition of refinements as scope-local.
class Avocado
def tasty?
true
end
end
module RefineAvocado
refine Avocado do
def call_tasty
method(:tasty?).call
end
def tasty?
false
end
end
end
The argument is that method() here should return the refined version of tasty? (the one that returns false). I don't see any justification for this.
The "method" method is defined on Object:
class Object
def method; ... end
end
At the point where "method" is called, exactly one refinement is active: the RefineAvocado module which adds "check_tasty" and overrides "tasty?". So "method" dispatches to Object#method.
Object#method is not refined, since it is not defined within a scope where refinements are active. It does not see refinements active in scopes earlier in the call stack, so it produces a reference to the original "tasty?" method.
What logic dictates that Object#method should now always be a refined method that has to inspect the stack?
If Object#method did reflect refinements active in the caller's scope, it would make it possible to get the refined method...but it would make it impossible to get the *original* method. And the same change has been proposed for all reflective access...the refinements basically make it impossible to inspect the original class, because they're in the way.
Giving Object#method and friends stack powers also makes them impossible to wrap. If you put your own code around Object#method, it will *never* see refinements because your wrapper's scope gets in the way. So if we made these class-hierarchy-related methods reflect refinements, you would no longer be able to safely wrap any of the following methods:
Symbol#to_proc
Object#send
Object#method
Object#methods
Object#respond_to?
Module#instance_method
Module#instance_methods
Module#public_instance_methods
Module#protected_instance_methods
Module#private_instance_methods
Module#method_defined?
Module#public_method_defined?
Module#private_method_defined?
Module#protected_method_defined?
Module#public_class_method
Module#private_class_method
Module#public_instance_method
Module#singleton_methods
Module#protected_methods
Module#private_methods
Module#public_methods
defined? logic for methods and super
And this may be just a start.
Instead, I propose that reflection of refinements be exposed directly.
Kernel#active_refinements => array of refinements active in the current scope, similar to Module#nesting
Object#refined_method(active_refinements, name)
=> returns a Method representing the refined method that would be found for the given list of refinements, or nil
Object#send_refined(active_refinements, name, *args)
=> sends the given name + args as though the specified refinements were active
I guess what I'm asking is that you consider a world where all of Ruby is implemented in Ruby, without stack-walking or magic, and don't make that world harder to achieve by adding magic to so many core methods. If people want a way to reflect from within a refined scope, give them those tools; don't change the semantics of the existing tools and give them new powers to inspect the call stack.
PROBLEM: to_proc and other coercions in relation to refinements
Some folks have said they think to_proc should reflect refinements. I also disagree here.
class Lemur
def scratch
puts "itchy itchy"
end
end
module RefineLemur
refine Lemur do
def scratch
"scratchy scratchy"
end
end
end
using RefineLemur
ary = [Lemur.new, Lemur.new]
ary.each &:scratch
This last line is essentially the same as &(:scratch.to_proc)
to_proc can be defined like this, in Ruby:
class Symbol
def to_proc
return proc {|obj| obj.send self}
end
end
It should be apparent why to_proc should not reflect refinements: the send call it makes does not live within a refined scope. You are getting a new proc in hand with logic to send that symbol to any object it is passed. Refinements don't enter into it.
If we return to the definition of refinements as scope-local prepends, there's no way to justify making to_proc reflect refinements. The scope where refinements are active leads up to the to_proc and each calls, but NO FURTHER. The to_proc call operates independent of the refined scope and cannot see refinements. Making it "special", so it can see up the call stack, would mean it can't be wrapped anymore, can't be implemented in Ruby. You are giving superpowers to a single core method that NO RUBY CODE CAN MIMIC.
We should not make yet more core class methods that are impossible to wrap or write in Ruby.
PROBLEM: scoping at file level, module level, or some other level
The main benefit from making refinements file-scoped is simplifying the refined lookup process. If refinements must all be specified at the top level, then we have a clear set of active refinements at any given time. If they're activated within scopes, it can get confusing:
using M1 # M1 is active
module Blah
using M2 # M1, M2 are active?
module Bubble
using M3 # M1, M2, M3 are active?
"string".some_call ...
end
using M4 # M1, M2, M4 are active?
end
# M1 is active
The overall effect on virtual-hierarchy method lookup is still basically the same. The refined modules are searched in most-recently-used order. The virtual hierarchy for the some_call call above would be:
[M3] < [M2] < [M1] < String < Object
If we implement it like Shugo's patch, the overlay modules are attached to the call sites as they are encountered, and only those overlays will ever be active at that call site.
So I guess I'm saying the file-level requirement simplifies some things, but doesn't really change anything conceptually.
PROBLEM: Matz's example showing String refinements active in a refine Array block
This example should not work:
module M1
refine String do
def foo; puts 'foo'; end
end
module M2
refine Array do
"string".foo
end
end
end
Within the M2 refinement, only one refinement is active: M2. M2 does live within M1, but M1's refinements are not active within the body of M1, and therefore they should not be active within the body of M2 or the refine Array block.
The virtual hierarchy at the point of the "foo" call looks like this because no active refinements affect String: String < Object
I would like to hear justification why the "foo" call above should succeed. It does not fit my mental model of refinements.
PROBLEM: module_eval
Several folks have claimed refinements will only be useful if they can be applied dynamically to module_eval blocks. However, this does not fit any reasonable definition of refinements thus far.
A block lives within a scope, and that scope may or may not have refinements active. You cannot change what refinements the block will see in the same way that you can't change what constants it will see. The following does not work:
module A
B = 1
end
A.module_eval { B } # => NameError: uninitialized constant B
And the following should not work either:
module A
refine String do
def foo; puts 'foo'; end
end
end
module B
using A
end
B.module_eval { "string".foo } # => NoMethodError
The foo call does not appear within a refined scope, and therefore it must never reflect refinements. I think it's just as important for this feature to know definitively when it *won't* happen as when it *will* happen, and it should NEVER be possible to force refinements on Other People's Code.
---
More to come as I think about stuff more. Is it possible for me to get access to edit the wiki page? I'd like to try to fill out more details (assuming I've got the details right).
----------------------------------------
Feature #4085: Refinements and nested methods
https://bugs.ruby-lang.org/issues/4085#change-34304
Author: shugo (Shugo Maeda)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
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
module Quux
using FooExt
foo = Foo.new
foo.bar # => FooExt#bar
foo.baz # => Foo#bar
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
--
http://bugs.ruby-lang.org/