<< §2.3.3 Smart lifting | ↑ Table of Contents ↑ | §2.3.5 Consequences of lifting problems >> |
§2.3.4 Binding ambiguities
While all examples so far have only shown 1-to-1 class bindings, several cases of multiple bindings are allowable. Ambiguities may be detected at compile time and/or at runtime.
(a) Potential ambiguity
A potential ambiguity is given,
if two role classes R1
and R2
exist such that
R1
andR2
are played by the same base classB
, andR1
andR2
have a common super roleR0
, which is also bound to a base classB0
, and- neither role class
R1
norR2
is a (indirect) sub-class of the other.
Effect:
In this case the compiler issues a warning, stating that theB
may not be liftable, because both role classes R1
and R2
are candidates and there is no reason to prefer one over the other.
If no potential ambiguity is detected, lifting will always be unambiguous.
In the above situation, trying to lift an instance of type B
to the role type
R0
is an illegal lifting request. If R0
is bound
to the same base class B
as its sub-roles R1
and R2
are,
role R0
is unliftable, meaning that no instance of R0
can ever by obtained by lifting.
Example code (Potential Ambiguity):
1 | team class MyTeam { |
2 | public class SuperRole playedBy MyBase {...} |
3 | public class SubRoleA extends SuperRole {...} |
4 | public class SubRoleB extends SuperRole {...} |
5 | } |
(b) Definite ambiguity
A definite ambiguity is given if
- the situation of potential ambiguity according to (a) above is given and
- lifting is requested (either by method binding or explicitly
(§2.3.2)) from the shared base class
B
to any role classR0
that is a common super role forR1
andR2
.
Definite binding ambiguity also occurs in cases of generic declared lifting §2.3.2.(e)
if the specified role R
is unbound and if two independent sub-roles R1
and R2
exist that introduce a playedBy binding to the same base class BX
.
In this case no potential ambiguity is flagged because roles R1
and R2
have no shared bound super-role.
Effect:
Code causing definite ambiguity is required to handleorg.objectteams.LiftingFailedException
.
In cases of definite binding ambiguity lifting will indeed fail except for some corner cases. Such corner cases may arise if lifting already finds an appropriate role in the cache or if an (indirect) subrole of the ambiguously bound role is an unambiguous lift target for the concrete type of the base object at run-time. See also §2.3.5.
Example code (Definite Ambiguity):
1 | team class MyTeam { |
2 | public class SuperRole playedBy MyBase {...} |
3 | public class SubRoleA extends SuperRole playedBy SubBase {...} |
4 | public class SubRoleB extends SuperRole playedBy SubBase {...} |
5 | |
6 | public void useSuperRole(SubBase as SuperRole r) {...} // must declare LiftingFailedException |
7 | } |
(c) Actual ambiguity
At runtime actual ambiguity may occur if for the dynamic type of a base to be lifted the conditions of (b) above hold accordingly. Actual ambiguity is only possible in cases reported by the compiler as potential or definite ambiguity.
Effect:
An actual ambiguity is reported at runtime by throwing aorg.objectteams.LiftingFailedException
.
Example code (Actual Ambiguity):
1 | import org.objectteams.LiftingFailedException; |
2 | team class MyTeam { |
3 | public class SuperRole playedBy MyBase {...} |
4 | public class SubRoleA extends SuperRole playedBy SubBase {...} |
5 | public class SubRoleB extends SuperRole playedBy SubBase {...} |
6 | |
7 | public void useSuperRole(MyBase as SuperRole r) throws LiftingFailedException {...} |
8 | } |
9 | // plus these calls: |
10 | MyTeam mt = new MyTeam(); |
11 | mt.useSuperRole(new SubBase()); // will throw a LiftingFailedException |
(d) Mismatching role
In cases of potential ambiguity another runtime error may occur: a mismatching role is encountered when a role is found in the cache, which is not conform to the required type. This happens, if the base object has previously been lifted to a type that is incompatible with the currently requested type.
Effect:
This is reported by throwing aorg.objectteams.WrongRoleException
.
Example code (Mismatching Role):
1 | import org.objectteams.LiftingFailedException; |
2 | team class MyTeam { |
3 | public class SuperRole playedBy MyBase {...} |
4 | public class SubRoleA extends SuperRole {...} |
5 | public class SubRoleB extends SuperRole {...} |
6 | |
7 | public void useRoleA(MyBase as SubRoleA r) throws LiftingFailedException {...} |
8 | public void useRoleB(MyBase as SubRoleB r) throws LiftingFailedException {...} |
9 | } |
10 | // plus these calls: |
11 | MyTeam mt = new MyTeam(); |
12 | MyBase b = new MyBase(); |
13 | mt.useRoleA(b); // creates a SubRoleA for b |
14 | mt.useRoleB(b); // finds the SubRoleA which is not compatible |
15 | // to the expected type SubRoleB. |
From the second item of §2.3.4.(a) follows, that for binding ambiguities different
role hierarchies are analyzed in isolation.
For this analysis only those role classes are considered that are bound to a
base class (directly using playedBy
or by inheriting this relation
from another role class).
I.e., two role classes that have no common bound super role will never cause
any ambiguity.
<< §2.3.3 Smart lifting | ↑ Table of Contents ↑ | §2.3.5 Consequences of lifting problems >> |