|
|
Table of |
§2. Role binding |
| §1. Teams and Roles |
![]() |
|
| Teams and Roles |
Classes that are defined with the modifier team
are called team classes, or teams for short.Direct inner classes of a team are called role classes, or roles for short. |
![]() |
|
| Role inheritance | Inheritance between teams introduces a special inheritance relationship between their contained roles. The rules of this implicit inheritance are given below (§ 1.3.1). |
![]() |
|
| Externalized role | Roles are generally confined to the context of their enclosing team instance. Subject to specific restrictions, a role may be passed outside its team using the concept of externalized roles. |
![]() |
|
team is a team class
(or team for short).
|
|
this with the name of the team class, as in:
|
public
or protected.
protected role can only be accessed from within the enclosing
team or any of its sub-teams. The actual border of encapsulation is the
enclosing team instance. The rules for protected roles are given
in §1.2.3 below.
public roles can ever be accessed outside their enclosing team.
Accessing a role outside the enclosing team instance is governed by the rules
of externalized roles, to be defined next (§1.2.2).
protected role members can be accessed from the enclosing
team only.
public role members grant unrestricted access.
public members can ever be accessed via an externalized role.
MyTeam.this is available for accessing the enclosing team instance.
Note, that already two levels of initialization are performed prior to role instantiation: static initialization of the (outer most) enclosing team class and instantiation of the enclosing team(s). Static initialization of a role class would add nothing new to this.
Normally, a team encapsulates its role against unwanted access from the outside. If roles are visible outside their enclosing team instance we speak of externalized roles.
Externalized roles are subject to specific typing rules in order to ensure, that role instances from different team instances cannot be mixed in inconsistent ways. In the presence of implicit inheritance (§1.3.1) inconsistencies could otherwise occur, which lead to typing errors that could only be detected at run-time. Externalized roles use the theory of "virtual classes", or more specifically "family polymorphism", in order to achieve the desired type safety. These theories use special forms of dependent types. Externalized roles have types that depend on a team instance.
§1.2.3 will deduce even stronger forms of encapsulation from the rules about externalized roles.
public role class can ever be
externalized.
anchor.Type the expression to the
left of the dot can be a simple name or a path. It must refer to an instance of a team class,
the type at the right hand side of the dot must be the simple name
of a role directly contained in the given team (including roles
that are acquired by implicit inheritance).final (i.e., immutable).
The type anchor can be a path v.f1.f2... where
v is any final variable and f1 ...
are final fields.
this
(referring to the team instance).
I.e., the following two declarations express the same:
this and Outer.this are always
final.tthis to denote
such implicit type anchors in error messages.
teamA.RoleX and teamB.RoleY
not only requires the role types to be compatible, but also
the team instances to be provably the same object.
The compiler must be able to statically analyze anchor identity.
this is substituted by the actual call target.
For role methods a reference of the form Outer.this
is substituted by the enclosing instance of the call target.
final identifier
to another final identifier are transitively
followed, i.e., if t1, t2 are final,
after an assignment t1=t2
the types t1.R and t2.R are considered
identical. Otherwise t1.R and t2.R
are incommensurable.playedBy clause of a role class
(see §2.1).
outer to be
declared final. The expression has the
type outer.Role following the rules of
externalized roles.Role in this expression must be a simple
(unqualified) name.
|
|
Action which is
used to associate the action of resetting a subscriber's credits
to a button or similar element in an application's GUI.
context (line 8) and parameter
bonus (line 10) serve as anchor for the type of
externalized roles.
subscriber (line 9) and parameter
subscr (line 11) store a Subscriber role outside the
FlightBonus team.
final and prior to the
role assignment a team assignment has taken place (line 12).clearCredits (line 16).
This method call is an example for implicit team activation
(§5.3(b)).
unshow
is for this call expanded to
context for
this). This proves identical types for actual and
formal parameters.
public or protected,
any role that is not public is a protected role which is encapsulated
by its enclosing team instance. This is enforced by these rules:
protected role class.
protected role class may not be used qualified,
neither by its enclosing type nor by a variable as type anchor.
I.e., it may never appear right of a dot (".") (cf. §1.2.2(a)).
this.
instanceof operator and type casts have extended
semantics for roles.
instanceof operator yields true only if
both components of the type match: the dynamic role type must be compatible
to the given static type, and also type anchors must be the same instance.
org.objectteams.RoleCastException.
team modifier as its first token.
enum.
team modifier.
|
||||||||||||||||||||
|
|
||||||||
|
org.objectteams.Team is the root of all team
classes. It is implicitly taken as the super-class of any team class that has no
explicit extends clause. If an explicit extends clause
is present in a team, the super-class must again be a team class. Conversely,
any subclass of a team (including org.objectteams.Team) must again
be a team.
Interface implementation is not affected by this rule.
Infrastructure provided by class org.objectteams.Team is presented in
§6.
|
|
T which extends a super-team S
has one role class T.R corresponding to each role S.R
of the super-team.
The new type T.R overrides R for the
context of T and its roles.
Acquisition of role classes can either be direct (see (b) below), or
it may involve overriding and implicit inheritance ((c) below).
In the above example the team S operates
on types S.R0, S.R1 and S.R2,
while T operates on types T.R0, T.R1
and T.R2.
T each role S.R of its
super-team S is available by the name T.R
without further declaration. In the lexical context of T also
the short name R refers to the role T.R.
The role R2 can be used in the sub-team T (line 13), because this role type is defined in the super class of the enclosing team.
R1 in T implicitly inherits all features of
R1 in S. This is, because its enclosing team
T extends the team S (line 11) and the role
definition uses the same name R1 (line 12).
Hence the attribute ok is available in the method
m() in T.R1 (line 14).
S.R and T.R are always incommensurable.T or one of its contained roles,
refers to a role R, R will always
resolve to T.R even if R was introduced in
a super-team of T and even if the specific line of code
was inherited from a super-team or one of its roles.
Only the dynamic type of the enclosing team-instance is used to determine
the correct role class (see below for an example).
A special case of dynamically binding role types relates to so-called class literals (see JLS 15.8.2). Role class literals are covered in §6.1(c).
The above is strictly needed only for cases involving implicit inheritance.
It may, however, help intuition, to also consider the directly acquired
role T.R in (b) to override the given role S.R.
In line 18 the implicitly inherited method n is called
with the result of an invocation of m. Although
n was defined in S (thus with argument type
S.R2, see line 6) in the context of T it
expects an argument of T.R2. This is correctly provided by
the invocation of m in the context of T.
super is still available
along regular inheritance, a call tsuper.m()
selects the version of m of the corresponding role
acquired from the super-team.
See § 2.4.2 for tsuper
in the context of role constructors.
tsuper can only be used to invoke a corresponding
version of the enclosing method or constructor, i.e., an expression
tsuper.m() may only occur within the method m
with both methods having the same signature
(see §2.3.2(b) for an exception,
where both methods have slightly different signatures).
R1 in T overrides the implicitly inherited method
m() from S.tsuper.m() calls the overridden method m()
from S.R1 (line 14).
extends)
this relation is inherited along implicit inheritance.
The role R1 in T has T.R0 as its implicitly inherited super class, because the corresponding role in the super-team extends R0 (line 3).
new not only the
type to instantiate is bound dynamically (cf. (e)), but also the constructor to
invoke is dynamically bound in accordance to the concrete
type.this(..) and
super(..) calls are, however, bound statically
with respect to explicit and implicit inheritance.
|
|
|
MyTeamA inherits from
Team (line 1).
MySubTeam.MyRole (§1.3.1(c); line 11).overrides the compiler would see a declaration:
protected class MyRole overrides MyTeamA.MyRole { ... }getRole() on myTeam (line 27, 20)
creates an instance of MySubTeam.MyRole because the
acquired role MyTeamA.MyRole is overridden by
MySubTeam.MyRole
following the rules of implicit inheritance (cf. §1.3.1(e)).
tsuper.print()
(line 15),
which selects the implementation of MyTeamA.MyRole.print.
extends. These restrictions
apply:
extends clause
(see §1.2.2(g)).extends clause
(see 1.3.1(g) above) only if the new super-class
is a sub-class of the class in the overridden extends clause.
Ie., an implicit sub-role may specialize the extends clause of its
implicit super-role.
tsuper constructor
(see §2.4.2).
implements declarations are additive, i.e., an implicit
sub-role may add more interfaces but has to implement all interfaces of
its implicit super-role, too.
|
team modifier,
it may contain roles at the next level of nesting.
RoleAndTeam starting in line 14
is a role of OuterTeam and at the same time a
team containing a further role InnerRoleteam, see above)
may contain
local types (see JLS 14.3 - in the example: class Local),
anonymous types
(JLS 15.9.5 - in the example: class defined in lines 18-20)
but no member types (JLS 8.5 - in the example: illegal class
IllegalMember).
OuterTeam.RoleAndTeamSub.InnerRole has two direct tsuper roles: OuterTeam.RoleAndTeam.InnerRole and SuperOuter.RoleAndTeamSub.InnerRole.
If now the method defined in lines 27-30 were missing, the enclosing class OuterTeam.RoleAndTeamSub.InnerRole would inherit the method foo defined in line 16, because the inner inheritance between RoleAndTeamSub and RoleAndTeam binds stronger than the outer inheritance between OuterTeam and SuperOuter.
tsuper (see §1.3.1(f) above) by a type name in order to select among different method version inherited from different implicit super classes.
A term OuterTeam.tsuper evaluates to the super-class, say SuperOuter, of an enclosing team "OuterTeam". A method call OuterTeam.tsuper.m() evaluates to the method version within SuperOuter that best corresponds to the current method containing the tsuper-call.
SuperOuter resolving to SuperOuter.RoleAndTeamSub.InnerRole.foo()| Language implementation: |
Virtual classes: Each role class is an overridable feature of
its enclosing team. Role classes are resolved by dynamic binding
with respect to the enclosing team instance. This implementation
requires multiple-inheritance in order to also allow regular
inheritance between roles of the same team. super
and tsuper select parent versions of a method along
the two dimensions of inheritance.
Copy inheritance: Role acquisition from a super-team has the effect
of copying a role definition T.R yielding a new
role Tsub.R. All role applications Rx
in the role copy refer to Tsub.Rx. Implicit role
inheritance extends a role copy in-place. Only the tsuper
construct allows to access the previous version of a method
(i.e. before in-place overriding).
|
|
Table of |
§2. Role binding |