You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The current Rakudo approach of resolving a FQN method call is to search for the requested method using method's self.WHAT (roughly). This leads to a number of ambiguities and possibly need reconsideration.
In a nutshell, what happens here is that Bar and Foo get two different conretizations of role R with two different copies of private attribute $!a. A qualified call to R::inc-a from Foo eventually gets dispatched to inc-a method on Bar's concretization and, correspondingly, increments Bar's copy of $!a. This could result in very frustating bugs related to intermix of qualified calls to roles and use of private attributes in class code.
While trying to fix this issue experimented with providing information about a method caller which we have at compile time. In other words, when dispatcher:<::> get's called it can request it's context package and perform lookup on that package. In the example above it would be class Foo. In more complex situations, that could as well be a role if a FQN call belongs to that role code.
Unfortunately, that's only a part of the problem. While working on implementation of #110 I also realized that dispatcher is actually unable to locate the correct type object to perform method lookup without actually known the concrete type (or concretization for that matter) of the caller code. Let's consider the following example:
role R1[::T] {
method foo { do-work }
}
role R2[::T] does R1[::T] {
method foo {
self.R1::foo
}
}
role R2 does R1[Type1] {
method foo {
self.R1::foo
}
}
class Foo does R1[Type2] does R2[Type3] {
method foo {
self.R2::foo;
}
}
class Bar is Foo does R2 {
method foo {
callsame;
}
}
To make long story short, my experiment with providing compile-time information about the caller type didn't help the dispatcher to locate to correct method object and Foo.new.foo was ending up resolving to R1[Type1] concretization despite Bar not being involved in any way except by consuming R2.
While the final outcome is rathe incidental here, it reveals the main problem: concretization isn't known at the compile time. Thus, dispatch is forced to operate on unparameterized role and therefore the result of method lookup is not guaranteed to be correct.
I can foresee one simple solution to this: fail as R1 is being applied twice and this can be considered ambiguous relaxed FQN lookup. But let's look at it from the point of view of distributed development where each role in question is being developed by independent people or organizations. The consuming class is, in turn, developed by a third party. From the point of view of the R2 developer there is no ambiguity in the name resolution. The same apply to the class developer: he doesn't see an immediate conflict. Moreover, his code could stem from the times when R2 did not do R1 consumption. Abrupt breakage of the code after a module update could come as a very unpleasant surprise. Sure, this could possibly be fixed by puning R1. But if it has stubs then rewrite would require an intermediate class which Foo can then inherit from. Hm...
So, here is the issue as I see it.
The text was updated successfully, but these errors were encountered:
Adding language as the outcome of this topic could result in more roast tests.
With regard to rakudo label, the problem is related to the implementation details of MOP. So far, experimenting in this area led me to a conclusion that the issue could be resolved by preserving concrete caller type object for subsequent dispatcher calls. The type object could be anything with HOW doing Metamodel::MethodContainer role.
The exact way of providing this information is yet to be determined. For experimental purposes I was considering fetching type information from find_method_qualified method or from a new method with similar functionality. Unfortunately, this solution is incomplete.
More correct path would be to have a symbol containing the type object in lexical scope of the FQN call. For parameterized roles it could possibly be done similarly to how type captures are provided. But this path I didn't explore yet and have no idea how things work here.
The current Rakudo approach of resolving a FQN method call is to search for the requested method using method's
self.WHAT
(roughly). This leads to a number of ambiguities and possibly need reconsideration.Example 1:
In a nutshell, what happens here is that
Bar
andFoo
get two different conretizations of roleR
with two different copies of private attribute$!a
. A qualified call toR::inc-a
fromFoo
eventually gets dispatched toinc-a
method onBar
's concretization and, correspondingly, incrementsBar
's copy of$!a
. This could result in very frustating bugs related to intermix of qualified calls to roles and use of private attributes in class code.While trying to fix this issue experimented with providing information about a method caller which we have at compile time. In other words, when
dispatcher:<::>
get's called it can request it's context package and perform lookup on that package. In the example above it would be classFoo
. In more complex situations, that could as well be a role if a FQN call belongs to that role code.Unfortunately, that's only a part of the problem. While working on implementation of #110 I also realized that dispatcher is actually unable to locate the correct type object to perform method lookup without actually known the concrete type (or concretization for that matter) of the caller code. Let's consider the following example:
To make long story short, my experiment with providing compile-time information about the caller type didn't help the dispatcher to locate to correct method object and
Foo.new.foo
was ending up resolving toR1[Type1]
concretization despiteBar
not being involved in any way except by consumingR2
.While the final outcome is rathe incidental here, it reveals the main problem: concretization isn't known at the compile time. Thus, dispatch is forced to operate on unparameterized role and therefore the result of method lookup is not guaranteed to be correct.
I can foresee one simple solution to this: fail as
R1
is being applied twice and this can be considered ambiguous relaxed FQN lookup. But let's look at it from the point of view of distributed development where each role in question is being developed by independent people or organizations. The consuming class is, in turn, developed by a third party. From the point of view of theR2
developer there is no ambiguity in the name resolution. The same apply to the class developer: he doesn't see an immediate conflict. Moreover, his code could stem from the times whenR2
did not doR1
consumption. Abrupt breakage of the code after a module update could come as a very unpleasant surprise. Sure, this could possibly be fixed by puningR1
. But if it has stubs then rewrite would require an intermediate class whichFoo
can then inherit from. Hm...So, here is the issue as I see it.
The text was updated successfully, but these errors were encountered: