<< §1.2 Role classes and objects | ↑ Table of Contents ↑ | §1.4 Name clashes >> |
§1.3 Acquisition and implicit inheritance of role classes
Every team class implicitly implements the predefined interface org.objectteams.ITeam
.
If a team class has no explicit extends
clause it implicitly extends org.objectteams.Team
,
thus providing implementations for the methods in org.objectteams.ITeam
.
If a team class extends a non-team class, the compiler implicitly adds implementations for all methods declared
in org.objectteams.ITeam
to the team class.
Any subclass of a team (including org.objectteams.Team
) must again be a team.
Interface implementation is not affected by this rule.
Infrastructure provided via interface org.objectteams.ITeam
is presented in §6.
§1.3.1 Acquisition and implicit inheritance of role classes
↑ §1.3
A team acquires all roles from its super-team. This relation is similar to inheritance of inner classes, but with a few decisive differences as defined next. Two implementation options are mentioned below, which can be used to realize the special semantics of role acquisition (virtual classes and copy inheritance).
Implicit role inheritance
1 | public team class S { |
2 | protected class R0 {...} |
3 | protected class R1 extends R0 { |
4 | boolean ok; |
5 | R2 m() {...} |
6 | void n(R2 r) {...} |
7 | } |
8 | protected class R2 {...} |
9 | } |
10 | public team class T extends S { |
11 | @Override protected class R1 { |
12 | R2 m() { |
13 | if(ok) { return tsuper.m(); } |
14 | else { return null; } |
15 | } |
16 | void doIt() { |
17 | n(m()); |
18 | } |
19 | } |
20 | } |
(a) Role class acquisition
A team 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).
(b) Direct role acquisition
Within a sub-team T
each role S.R
of its
super-team S
is available by the simple name R
without further declaration.
R2
in Listing 1.3.1-1 can be used in the sub-team
T
(line 12), because this role type is defined in the super class of the enclosing team.
(c) Overriding and implicit inheritance
If a team contains a role class definition by the same name as a role defined in its super-team, the new role class overrides the corresponding role from the super-team and implicitly inherits all of its features. Such relation is established only by name correspondence.
A role that overrides an inherited role should be marked with an @Override
annotation.
A compiler should optionally flag a missing @Override
annotation with a warning.
Conversely, it is an error if a role is marked with an @Override
annotation but does not actually
override an inherited role.
It is an error to override a role class with an interface or vice versa. A final role cannot be overridden.
Unlike regular inheritance, constructors are also inherited
along implicit inheritance, and can be overridden just like normal methods.
R1
in T
implicitly inherits all features of
R1
in S
. This is, because its enclosing team
T
extends the team S
(line 10) and the role
definition uses the same name R1
(line 11).
Hence the attribute ok
is available in the method
m()
in T.R1
(line 13). T.R1
also overrides S.R1
which is marked by the @Override
annotation in line 11.
(d) Lack of subtyping
Direct acquisition of roles from a super-team and implicit inheritance
do not establish a subtype relation.
A role of a given team is never conform (i.e., substitutable)
to any role of any other team.
S.R
and T.R
are always incommensurable.
Note, that this rule is a direct consequence of §1.2.2.(e).
(e) Dynamic binding of types
Overriding an acquired role by a new role class has the following
implication: If an expression or declaration, which is evaluated on behalf of
an instance of team 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
.
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
.
(f) tsuper
Super calls along implicit inheritance use the new keyword
tsuper. While 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 team T
overrides the implicitly inherited method m()
from S
. tsuper.m()
calls the overridden method m()
from S.R1
(line 13).
(g) Implicitly inheriting super-types
If a role class has an explicit super class (using extends
)
this relation is inherited along implicit inheritance.
R1
in T
has T.R0
as its implicitly inherited super class, because the corresponding role in the super-team
extends R0
(line 3).
Overriding an implicitly inherited super class is governed by
§1.3.2.(b), below.
The list of implemented interfaces is merged along implicit
inheritance.
(h) Preserving visibility
A role class must provide at least as much access as the implicit super role, or a compile-time error occurs (this is in analogy to JLS §8.4.6.3). Access rights of methods overridden by implicit inheritance follow the same rules as for normal overriding.
(i) Dynamic binding of constructors
When creating a role instance using new
not only the
type to instantiate is bound dynamically (cf. §1.3.1.(e)), but also the constructor to
invoke is dynamically bound in accordance to the concrete
type.
Within role constructors all this(..)
and
super(..)
calls are bound statically with respect to explicit inheritance
and dynamically with respect to implicit inheritance. This means the target role name is
determined statically, but using that name the suitable role type is determined
using dynamic binding.
See also §2.5.(a) on using constructors of abstract role classes.
(j) Overriding and compatibility
The rules of JLS §8.4.6 also apply to methods and constructors inherited via implicit inheritance.
(k) Covariant return types
Given a team T1
with two roles R1
and R2
where R2
explicitly inherits from R1
, both roles defining
a method m
returning some type A
.
Given also a sub-team of T1
, T2
, where T2.R1
overrides m
with a covariant return type B
(sub-type of A
):
public team class T1 {
protected abstract class R1 {
abstract A m();
}
protected class R2 extends R1 {
A m() { return new A(); }
}
}
public team class T2 extends T1 {
protected class R1 {
@Override B m() { return new B(); } // this declaration renders class T2.R2 illegal
}
}
In this situation role T2.R2
will be illegal unless also overriding m
with a return type that is at least B
.
Note, that the actual error occurs at the implicitly inherited method T2.R2.m
which is not visible in the source code,
even T2.R2
need not be mentioned explicitly in the source code.
A compiler should flag this as an imcompatibility at the team level, because a team must specialize inherited roles
in a consistent way.
Example code (Teams and Roles):
1 | public team class MyTeamA { |
2 | protected class MyRole { |
3 | String name; |
4 | public MyRole (String n) { name = n; } |
5 | public void print() { System.out.println("id="+name); } |
6 | } |
7 | protected MyRole getRole() { return new MyRole("Joe"); } |
8 | } |
10 | public team class MySubTeam extends MyTeamA { |
11 | protected class MyRole { |
12 | int age; |
13 | public void setAge(int a) { age = a; } |
14 | public void print() { |
15 | tsuper.print(); |
16 | System.out.println("age="+age); |
17 | } |
18 | } |
19 | public void doit() { |
20 | MyRole r = getRole(); |
21 | r.setAge(27); |
22 | r.print(); |
23 | } |
24 | } |
25 | ... |
26 | MySubTeam myTeam = new MySubTeam(); |
27 | myTeam.doit(); |
Program output
id=Joe age=27
Effects:
- According to §1.3,
MyTeamA
implementsITeam
(line 1). - An implicit role inheritance is created for
MySubTeam.MyRole
(§1.3.1.(c); line 11).
If we visualize this special inheritance using a fictitious keywordoverrides
the compiler would see a declaration:protected class MyRole overrides MyTeamA.MyRole { ... }
- Invoking
getRole()
onmyTeam
(line 27, 20) creates an instance ofMySubTeam.MyRole
because the acquired roleMyTeamA.MyRole
is overridden byMySubTeam.MyRole
following the rules of implicit inheritance (cf. §1.3.1.(e)). - Overriding of role methods and access to inherited features works as usual.
- As an example for §1.3.1.(f) see the call
tsuper.print()
(line 15), which selects the implementation ofMyTeamA.MyRole.print
.
§1.3.2 Regular role inheritance
↑ §1.3
In addition to implicit inheritance, roles may also inherit using
the standard Java keyword extends
. These restrictions apply:
(a) Super-class restrictions
If the super-class of a role is again a role it must be a direct role of
an enclosing team
This rule is simply enforced by disallowing type anchors in the
extends
clause
(see §1.2.2.(g)).
As an effect, the super-class may never be more deeply nested than the sub-class.
(b) Inheriting and overriding the extends clause
If a role overrides another role by implicit inheritance, it may
change the inherited 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.
I.e., an implicit sub-role may specialize the extends clause of its
implicit super-role.
(c) Constructors and overridden 'extends' 
Each constructor of a role class that overrides the extends clause of its
implicit super-role must invoke a constructor of this newly introduced
explicit super-class. Thus it may not use a tsuper
constructor
(see §2.4.2).
<< §1.2 Role classes and objects | ↑ Table of Contents ↑ | §1.4 Name clashes >> |
S
operates on typesS.R0
,S.R1
andS.R2
, whileT
operates on typesT.R0
,T.R1
andT.R2
.(Type references like "
S.R0
" are actually illegal in source code (§1.2.3.(b)). Here they are used for explanatory purposes only)