Bug #13271
closed
Clarifications on refinement spec
Added by Gondolin (Damien Robert) over 7 years ago.
Updated almost 7 years ago.
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 of M1
but also the refinements of the included module M2
.
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 of mod
" it looks like the spec only speak about the refined modules in M1
.
-
As noted in the spec, refinement:Foo@M1
should behave as if its superclass was Foo
, so the fact that Foo.new.foo
does not go through the refinements of M2
was expected.
However I find the result of 'Foo.new.bar
' strange: refinement:Foo@M1
does not contain the bar method, but its included module R1
does. So should not the result be
R1#bar -> Foo#bar
, whithout going through the refinements methods of M2
?
The spec states "(3) If C
has included modules, for these modules M
If a method with name N
found in the method table of M
, 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
and Bar.new.bar
. According to the spec:
"(7) If C
has a direct superclass, search the method N
as specified in "Normal method lookup" from Step 4, where C
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
- Status changed from Open to Assigned
- Assignee set to shugo (Shugo Maeda)
- Description updated (diff)
Gondolin (Damien Robert) wrote:
- As I was expecting, '
using M1
' not only activate the refinements of M1
but also the refinements of the included module M2
.
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 of mod
" it looks like the spec only speak about the refined modules in M1
.
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 was Foo
, so the fact that Foo.new.foo
does not go through the refinements of M2
was expected.
However I find the result of 'Foo.new.bar
' strange: refinement:Foo@M1
does not contain the bar method, but its included module R1
does. So should not the result be
R1#bar -> Foo#bar
, whithout going through the refinements methods of M2
?
The spec states "(3) If C
has included modules, for these modules M
If a method with name N
found in the method table of M
, 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
and Bar.new.bar
. According to the spec:
"(7) If C
has a direct superclass, search the method N
as specified in "Normal method lookup" from Step 4, where C
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.
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!
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 of M
?
Yes.
This behavior seems strange, and may be a bug of the implementation.
Ok!
I'll investigate further.
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 of M
?
Yes.
Sorry, it's wrong:(
The behavior was changed by Feature #8571.
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?
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.
- Status changed from Assigned to Closed
Applied in changeset trunk|r60992.
Specify refinement inheritance by Module#include.
[ruby-core:79880] [Bug #13271]
Also available in: Atom
PDF
Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0