Bug #13271
closedClarifications on refinement spec
Description
Consider the following code:
class Foo
def foo
"Foo#foo"
end
def bar
"Foo#bar"
end
end
class Bar < Foo
def foo
"Bar#foo -> "+super
end
def bar
"Bar#bar -> "+super
end
end
module R1
def foo
"R1#foo -> "+super
end
def bar
"R1#bar -> "+super
end
end
module R2
def foo
"R2#foo -> "+super
end
def bar
"R2#bar -> "+super
end
end
module M2
refine Foo do
include R2
def foo
"refinement:Foo@M2#foo -> "+super
end
def bar
"refinement:Foo@M2#bar -> "+super
end
end
end
module M1
include M2
refine Foo do
include R1
def foo
"refinement:Foo@M1#foo -> "+super
end
end
end
using M1
puts Foo.new.foo #refinement:Foo@M1#foo -> R1#foo -> Foo#foo
puts Foo.new.bar #R1#bar -> refinement:Foo@M2#bar -> R2#bar -> Foo#bar
puts Bar.new.foo #Bar#foo -> Foo#foo
puts Bar.new.bar #Bar#bar -> Foo#bar
I have several questions about the results.
-
As I was expecting, '
using M1' not only activate the refinements ofM1but also the refinements of the included moduleM2.
In other word it behaves as if I had specified 'using M2; using M1'. This is what I was expecting but from reading the spec
"(3) Activate refinements in the defined refinement table ofmod" it looks like the spec only speak about the refined modules inM1. -
As noted in the spec,
refinement:Foo@M1should behave as if its superclass wasFoo, so the fact thatFoo.new.foodoes not go through the refinements ofM2was expected.
However I find the result of 'Foo.new.bar' strange:refinement:Foo@M1does not contain the bar method, but its included moduleR1does. So should not the result be
R1#bar -> Foo#bar, whithout going through the refinements methods ofM2?
The spec states "(3) IfChas included modules, for these modulesMIf a method with nameNfound in the method table ofM, return the method."
But it does not stipulate what happen if we call super in one of these included method. -
I am also surprised by the behaviour of
Bar.new.fooandBar.new.bar. According to the spec:
"(7) IfChas a direct superclass, search the methodNas specified in "Normal method lookup" from Step 4, whereCis the superclass."
and Step 4 start by looking at the activated refinements.So I was expecting the results to go through
Foo's refinement, so that for instance 'Bar.new.foo' would be
Bar#foo -> refinement:Foo@M1#foo -> R1#foo -> Foo#foo
Updated by shyouhei (Shyouhei Urabe) over 8 years ago
- Status changed from Open to Assigned
- Assignee set to shugo (Shugo Maeda)
Updated by nobu (Nobuyoshi Nakada) over 8 years ago
- Description updated (diff)
Updated by shugo (Shugo Maeda) over 8 years ago
Gondolin (Damien Robert) wrote:
- As I was expecting, '
using M1' not only activate the refinements ofM1but also the refinements of the included moduleM2.
In other word it behaves as if I had specified 'using M2; using M1'. This is what I was expecting but from reading the spec
"(3) Activate refinements in the defined refinement table ofmod" it looks like the spec only speak about the refined modules inM1.
The behavior of my first proposal was what you expected, but it was changed to reduce implicit effects of refinements.
- As noted in the spec,
refinement:Foo@M1should behave as if its superclass wasFoo, so the fact thatFoo.new.foodoes not go through the refinements ofM2was expected.
However I find the result of 'Foo.new.bar' strange:refinement:Foo@M1does not contain the bar method, but its included moduleR1does. So should not the result be
R1#bar -> Foo#bar, whithout going through the refinements methods ofM2?
The spec states "(3) IfChas included modules, for these modulesMIf a method with nameNfound in the method table ofM, return the method."
But it does not stipulate what happen if we call super in one of these included method.
This behavior seems strange, and may be a bug of the implementation.
I am also surprised by the behaviour of
Bar.new.fooandBar.new.bar. According to the spec:
"(7) IfChas a direct superclass, search the methodNas specified in "Normal method lookup" from Step 4, whereCis the superclass."
and Step 4 start by looking at the activated refinements.So I was expecting the results to go through
Foo's refinement, so that for instance 'Bar.new.foo' would be
Bar#foo -> refinement:Foo@M1#foo -> R1#foo -> Foo#foo
refinement:Foo@M1 is not active in the definitions of Bar#foo and Bar#bar, so super in them
never invoke refinement:Foo@M1#foo.
Updated by Gondolin (Damien Robert) over 8 years ago
Thanks for the answers!
shugo (Shugo Maeda) wrote:
The behavior of my first proposal was what you expected, but it was changed to reduce implicit effects of refinements.
So should I expect that in future ruby versions using M will not also activate the refinements of included and prepended modules of M?
This behavior seems strange, and may be a bug of the implementation.
Ok!
refinement:Foo@M1 is not active in the definitions of Bar#foo and Bar#bar, so super in them
never invoke refinement:Foo@M1#foo.
Oh of course, the definition of Bar#foo is in a lexical scope where the refinements were not active, so since refinements work with the lexical scope they won't be activated there, thanks!
Updated by shugo (Shugo Maeda) over 8 years ago
Gondolin (Damien Robert) wrote:
The behavior of my first proposal was what you expected, but it was changed to reduce implicit effects of refinements.
So should I expect that in future ruby versions
using Mwill not also activate the refinements of included and prepended modules ofM?
Yes.
This behavior seems strange, and may be a bug of the implementation.
Ok!
I'll investigate further.
Updated by shugo (Shugo Maeda) over 8 years ago
shugo (Shugo Maeda) wrote:
Gondolin (Damien Robert) wrote:
The behavior of my first proposal was what you expected, but it was changed to reduce implicit effects of refinements.
So should I expect that in future ruby versions
using Mwill not also activate the refinements of included and prepended modules ofM?Yes.
Sorry, it's wrong:(
The behavior was changed by Feature #8571.
Updated by Gondolin (Damien Robert) over 8 years ago
shugo (Shugo Maeda) wrote:
The behavior was changed by Feature #8571.
Well I prefer that this feature remains so that's nice! But this probably means that the spec should be updated then?
Updated by shugo (Shugo Maeda) over 8 years ago
Gondolin (Damien Robert) wrote:
shugo (Shugo Maeda) wrote:
The behavior was changed by Feature #8571.
Well I prefer that this feature remains so that's nice! But this probably means that the spec should be updated then?
Yes. I'll update doc/syntax/refinements.rdoc after investigating 2) further.
Updated by shugo (Shugo Maeda) almost 8 years ago
- Status changed from Assigned to Closed
Applied in changeset trunk|r60992.
Specify refinement inheritance by Module#include.
[ruby-core:79880] [Bug #13271]