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 ofM1
but 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@M1
should behave as if its superclass wasFoo
, so the fact thatFoo.new.foo
does not go through the refinements ofM2
was expected.
However I find the result of 'Foo.new.bar
' strange:refinement:Foo@M1
does not contain the bar method, but its included moduleR1
does. So should not the result be
R1#bar -> Foo#bar
, whithout going through the refinements methods ofM2
?
The spec states "(3) IfC
has included modules, for these modulesM
If a method with nameN
found 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.foo
andBar.new.bar
. According to the spec:
"(7) IfC
has a direct superclass, search the methodN
as specified in "Normal method lookup" from Step 4, whereC
is 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 7 years ago
- Status changed from Open to Assigned
- Assignee set to shugo (Shugo Maeda)
Updated by shugo (Shugo Maeda) over 7 years ago
Gondolin (Damien Robert) wrote:
- As I was expecting, '
using M1
' not only activate the refinements ofM1
but 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@M1
should behave as if its superclass wasFoo
, so the fact thatFoo.new.foo
does not go through the refinements ofM2
was expected.
However I find the result of 'Foo.new.bar
' strange:refinement:Foo@M1
does not contain the bar method, but its included moduleR1
does. So should not the result be
R1#bar -> Foo#bar
, whithout going through the refinements methods ofM2
?
The spec states "(3) IfC
has included modules, for these modulesM
If a method with nameN
found 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.foo
andBar.new.bar
. According to the spec:
"(7) IfC
has a direct superclass, search the methodN
as specified in "Normal method lookup" from Step 4, whereC
is 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 7 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 7 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 M
will 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 7 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 M
will 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 7 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 7 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 7 years ago
- Status changed from Assigned to Closed
Applied in changeset trunk|r60992.
Specify refinement inheritance by Module#include.
[ruby-core:79880] [Bug #13271]