Project Manifold (Forwarding and Delegation)

yanngaelgueheneuc 109 views 55 slides Oct 11, 2024
Slide 1
Slide 1 of 55
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55

About This Presentation

The manifold-delegation project is a compiler plugin that provides language support for call forwarding and true delegation. These features are an experimental effort toward interface composition as a practical alternative to implementation inheritance. This presentation shows problems with forwardi...


Slide Content

Yann-Gaël Guéhéneuc
(/jan/, he/il)
Work licensed under Creative Commons
BY-NC-SA 4.0 International
Project Manifold
(Forwarding
and Delegation)
[email protected]
Version 0.2
2024/10/09

2/55
Fragile Base Class Problem 
Joshua Bloch ;
Effective Java ;
Prentice Hall, 2nd
edition (May 28, 2008)

3/55
FORWARDING

4/55
Requirements –Need 
Implement a Set
that counts the number of added elements,
which is differentfrom the current number of
elements,
e.g., for performance tuning

5/55
Requirements –Client Code public class
Main {
public static void
main(
final
String[]
args
) {
final
CountingHashSet<String>
s
=
new
CountingHashSet<String>();
s
.addAll(Arrays.asList(
"Rick Deckard"
,
"Roy Batty"
,
"Pris Stratton"
,
"Zhora Salome"
,
"Leon Kowalski"
,
"Rachael"
));
s
.remove(
"Leon Kowalski"
);
s
.remove(
"Zhora Salome"
);
s
.remove(
"Pris Stratton"
);
s
.remove(
"Roy Batty"
);
s
.add(
"Tyrell"
);
System.
out
.print(
"Was expected 7, got "
);
System.
out
.println(
s
.getAddCount());
}
}

6/55
Requirements –Client Code
7? 13?
public class
Main {
public static void
main(
final
String[]
args
) {
final
CountingHashSet<String>
s
=
new
CountingHashSet<String>();
s
.addAll(Arrays.asList(
"Rick Deckard"
,
"Roy Batty"
,
"Pris Stratton"
,
"Zhora Salome"
,
"Leon Kowalski"
,
"Rachael"
));
s
.remove(
"Leon Kowalski"
);
s
.remove(
"Zhora Salome"
);
s
.remove(
"Pris Stratton"
);
s
.remove(
"Roy Batty"
);
s
.add(
"Tyrell"
);
System.
out
.print(
"Was expected 7, got "
);
System.
out
.println(
s
.getAddCount());
}
}

7/55
Given –Set Interface public interface
Set
extends
Collection {
int
size();
boolean
isEmpty();
boolean
contains(Object
o
);
Iterator iterator();
Object[] toArray();
Object[] toArray(Object
a
[]);
boolean
add(Object
o
);
boolean
remove(Object
o
);
boolean
containsAll(Collection
c
);
boolean
addAll(Collection
c
);
boolean
retainAll(Collection
c
);
boolean
removeAll(Collection
c
);
void
clear();
boolean
equals(Object
o
);
int
hashCode();
}

8/55
Given –HashSet Implementation public class
HashSet<E>
extends
AbstractSet<E>
implements
Set<E>, Cloneable, java.io.Serializable {
private transient
HashMap<E,Object>
map
;
public
HashSet() {
map
=
new
HashMap<>();
}
public
Iterator<E> iterator() {
return
map
.keySet().iterator();
}
public int
size() {
return
map
.size();
}
...

9/55
Solution 
Straightforward solution
–Reuse of code
–Subtyping

10/55
Solution –First Implementation public class
CountingHashSet<E>
extends
HashSet<E>
implements
CountingSet<E> {
? @Override public boolean
add(
final
E
e
) {
?
?
}@Override public boolean
addAll(
final
Collection<?
extends
E>
c
) {
?
?
}@Override public int
getAddCount() {
?
}
}

11/55
Solution –First Implementation public class
CountingHashSet<E>
extends
HashSet<E>
implements
CountingSet<E> {
private int
addCount
= 0;
@Override public boolean
add(
final
E
e
) {
this
.
addCount
++;
return super
.add(
e
);
}
@Override public boolean
addAll(
final
Collection<?
extends
E>
c
) {
this
.
addCount
+=
c
.size();
return super
.addAll(
c
);
}
@Override public int
getAddCount() {
return this
.
addCount
;
}
}

12/55
Solution –First Implementation 
Broken!

13/55
Solution –First Implementation 
Broken!
–Method addAll()calls add(), which implies
that added elements will be counted twice!

14/55
Solution –First Implementation 
Broken!
–Method addAll()calls add(), which implies
that added elements will be counted twice!
–You could
NOT
know that, without either reading
the source code of HashSetor testing your
implementation of CountingHashSet

15/55
Solution –First Implementation 
Broken!
–Method addAll()calls add(), which implies
that added elements will be counted twice!
–You could
NOT
know that, without either reading
the source code of HashSetor testing your
implementation of CountingHashSet
–What if you did
NOT
have access to the source
code of HashSet?

16/55
Fragile Base Class Problem 
The
provider
cannot determine whether a
change to a base class is
safe
for
users
by
examining in isolation the methods of the
base class

The
user
cannot determine whether
extending the base class is
safe
by reading
the API of the base class
–Must study its implementation

17/55
Solution –Second Implementation 

Problem: fragile base class problem
Solution: favour composition over inheritance

18/55
Solution –Second Implementation 
Favour
composition
over
inheritance
– Allow changing implementation
– Allow
safe
inheritance

Problem: fragile base class problem
Solution: favour composition over inheritance

19/55
Solution –Second Implementation 
Favour
composition
over
inheritance
– Allow changing implementation
– Allow
safe
inheritance

Add one level of indirection
– A ForwardingSetdelegates to HashSet
– Composite delegates to component
– CountingHashSetextends ForwardingSet
Problem: fragile base class problem
Solution: favour composition over inheritance

20/55

Add one level of indirection
– ForwardingSetdelegates to HashSet
• Composite delegates to component
– CountingHashSetextends ForwardingSet
Solution –Second Implementation

21/55
Solution –Second
Implementation
public class
ForwardingSet<E>
implements
Set<E> {
private final
Set<E>
s
=
new
HashSet<E>();
public void
clear(){
s
.clear(); }
public boolean
contains(
final
Object
o
) {
return
s
.contains(
o
); }
public boolean
isEmpty(){
return
s
.isEmpty(); }
public int
size(){
return
s
.size(); }
public
Iterator<E> iterator() {
return
s
.iterator(); }
public boolean
add(
final
E
e
) {
return
s
.add(
e
); }
public boolean
remove(
final
Object
o
) {
return
s
.remove(
o
); }
public boolean
containsAll(
final
Collection<?>
c
) {
return
s
.containsAll(
c
); }
public boolean
addAll(
final
Collection<?
extends
E>
c
) {
return
s
.addAll(
c
); }
public boolean
removeAll(
final
Collection<?>
c
) {
return
s
.removeAll(
c
); }
public boolean
retainAll(
final
Collection<?>
c
) {
return
s
.retainAll(
c
); }
public
Object[] toArray(){
return
s
.toArray(); }
public
<T> T[] toArray(
final
T[]
a
) {
return
s
.toArray(
a
); }
public boolean
equals(
final
Object
o
) {
return
s
.equals(
o
); }
public int
hashCode(){
return
s
.hashCode(); }
public
String toString(){
return
s
.toString(); }
}

22/55
Solution –Second
Implementation
Typical delegations
public class
ForwardingSet<E>
implements
Set<E> {
private final
Set<E>
s
=
new
HashSet<E>();
public void
clear(){
s
.clear(); }
public boolean
contains(
final
Object
o
) {
return
s
.contains(
o
); }
public boolean
isEmpty(){
return
s
.isEmpty(); }
public int
size(){
return
s
.size(); }
public
Iterator<E> iterator() {
return
s
.iterator(); }
public boolean
add(
final
E
e
) {
return
s
.add(
e
); }
public boolean
remove(
final
Object
o
) {
return
s
.remove(
o
); }
public boolean
containsAll(
final
Collection<?>
c
) {
return
s
.containsAll(
c
); }
public boolean
addAll(
final
Collection<?
extends
E>
c
) {
return
s
.addAll(
c
); }
public boolean
removeAll(
final
Collection<?>
c
) {
return
s
.removeAll(
c
); }
public boolean
retainAll(
final
Collection<?>
c
) {
return
s
.retainAll(
c
); }
public
Object[] toArray(){
return
s
.toArray(); }
public
<T> T[] toArray(
final
T[]
a
) {
return
s
.toArray(
a
); }
public boolean
equals(
final
Object
o
) {
return
s
.equals(
o
); }
public int
hashCode(){
return
s
.hashCode(); }
public
String toString(){
return
s
.toString(); }
}

23/55
Solution –Second
Implementation
public class
CountingHashSet<E>
extends
ForwardingSet<E>
implements
CountingSet<E> {
private int
addCount
= 0;
@Override public boolean
add(
final
E
e
) {
this
.
addCount
++;
return super
.add(
e
);
}
@Override public boolean
addAll(
final
Collection<?
extends
E>
c
) {
this
.
addCount
+=
c
.size();
return super
.addAll(
c
);
}
@Override public int
getAddCount() {
return this
.
addCount
;
}
}

24/55
Solution –Second
Implementation
public class
CountingHashSet<E>
extends
ForwardingSet<E>
implements
CountingSet<E> {
private int
addCount
= 0;
@Override public boolean
add(
final
E
e
) {
this
.
addCount
++;
return super
.add(
e
);
}
@Override public boolean
addAll(
final
Collection<?
extends
E>
c
) {
this
.
addCount
+=
c
.size();
return super
.addAll(
c
);
}
@Override public int
getAddCount() {
return this
.
addCount
;
}
}
Same as first solution but for this

25/55
Solution –Second
Implementation

Forwarding involves twodistinctobjects
–Notoneobjectanditssuperclass

thisrefers alternatively
–Totheinstanceof
CountingHashSet
–Tothe(unrelated) instance of
HashSet

26/55
Solution –Third
Implementation

Project Manifold
–“Manifold is a Java compiler plugin, its features
include Metaprogramming, Properties,
Extension Methods, Operator Overloading,
Templates, a Preprocessor, and more.”
–https://github.com/manifold-systems

27/55
Solution –Third
Implementation

Manifold Delegation
–“The manifold-delegation project is a compiler
plugin that provides language support for call
forwarding and true delegation. These features
are an experimental effort toward interface
composition as a practical alternative to
implementation inheritance.”
–https://github.com/manifold-systems/manifold/
tree/master/manifold-deps-parent/manifold-
delegation

28/55
Solution –Third
Implementation

Manifold Delegation
–“The manifold-delegation project is a compiler
plugin that provides language support for call
forwarding and true delegation. These features
are an experimental effort toward
interface
composition as a practical alternative to
implementation inheritance
.”
–https://github.com/manifold-systems/manifold/
tree/master/manifold-deps-parent/manifold-
delegation

29/55
Solution –Third
Implementation

True forwarding
–Declare
CountingHashSet
has a forwarder to
HashSet
, i.e., imply same interface (API)
–Override some calls between instances of
CountingHashSet
and instances of
HashSet

30/55
Solution –Third
Implementation
public class
CountingHashSet<E>
implements
CountingSet<E> {
@link
HashSet<E>
s
;
private int
addCount
= 0;
public
CountingHashSet() {
this
.
s
=
new
HashSet<E>();
}
@Override public boolean
add(
final
E
e
) {
this
.
addCount
++;
return this
.
s
.add(
e
);
}
@Override public boolean
addAll(
final
Collection<?
extends
E>
c
) {
this
.
addCount
+=
c
.size();
return this
.
s
.addAll(
c
);
}
@Override
public int
getAddCount() {
return this
.
addCount
;
}
}

31/55
Solution –Third
Implementation
public class
CountingHashSet<E>
implements
CountingSet<E> {
@link
HashSet<E>
s
;
private int
addCount
= 0;
public
CountingHashSet() {
this
.
s
=
new
HashSet<E>();
}
@Override public boolean
add(
final
E
e
) {
this
.
addCount
++;
return this
.
s
.add(
e
);
}
@Override public boolean
addAll(
final
Collection<?
extends
E>
c
) {
this
.
addCount
+=
c
.size();
return this
.
s
.addAll(
c
);
}
@Override
public int
getAddCount() {
return this
.
addCount
;
}
}CountingHashSetis a
Setthrough CountingSet

32/55
Solution –Third
Implementation
public class
CountingHashSet<E>
implements
CountingSet<E> {
@link
HashSet<E>
s
;
private int
addCount
= 0;
public
CountingHashSet() {
this
.
s
=
new
HashSet<E>();
}
@Override public boolean
add(
final
E
e
) {
this
.
addCount
++;
return this
.
s
.add(
e
);
}
@Override public boolean
addAll(
final
Collection<?
extends
E>
c
) {
this
.
addCount
+=
c
.size();
return this
.
s
.addAll(
c
);
}
@Override
public int
getAddCount() {
return this
.
addCount
;
}
}CountingHashSetis a
Setthrough CountingSet
Forwards most calls on one HashSet

33/55
Solution –Third
Implementation
public class
CountingHashSet<E>
implements
CountingSet<E> {
@link
HashSet<E>
s
;
private int
addCount
= 0;
public
CountingHashSet() {
this
.
s
=
new
HashSet<E>();
}
@Override public boolean
add(
final
E
e
) {
this
.
addCount
++;
return this
.
s
.add(
e
);
}
@Override public boolean
addAll(
final
Collection<?
extends
E>
c
) {
this
.
addCount
+=
c
.size();
return this
.
s
.addAll(
c
);
}
@Override
public int
getAddCount() {
return this
.
addCount
;
}
}CountingHashSetis a
Setthrough CountingSet
Forwards most calls on one HashSet
Overrides safely some methods

34/55
Solution –Third
Implementation
public class
CountingHashSet<E>
implements
CountingSet<E> {
@link
HashSet<E>
s
;
private int
addCount
= 0;
public
CountingHashSet() {
this
.
s
=
new
HashSet<E>();
}
@Override public boolean
add(
final
E
e
) {
this
.
addCount
++;
return this
.
s
.add(
e
);
}
@Override public boolean
addAll(
final
Collection<?
extends
E>
c
) {
this
.
addCount
+=
c
.size();
return this
.
s
.addAll(
c
);
}
@Override
public int
getAddCount() {
return this
.
addCount
;
}
}

35/55
Solution –Third
Implementation
<
dependencies
>
<
dependency
>
<
groupId
>systems.manifold</
groupId
>
<
artifactId
>manifold-delegation-rt</
artifactId
>
<
version
>${manifold.version}</
version
>
</
dependency
>
</
dependencies
>
<
build
>
<
plugins
>
<
plugin
>
<groupId
>org.apache.maven.plugins</
groupId
>
<
artifactId
>maven-compiler-plugin</
artifactId
>
<
version
>3.13.0</
version
>
<
configuration
>
<
source
>17</
source
>
<
target
>17</
target
>
<
compilerArgs
><
arg
>-Xplugin:Manifold</
arg
></
compilerArgs
>
<
annotationProcessorPaths
>
<
path
>
<
groupId
>systems.manifold</
groupId
>
<
artifactId
>manifold-delegation</
artifactId
>
<
version
>${manifold.version}</
version
>
</
path
>
</
annotationProcessorPaths
>
</
configuration
>
</
plugin
>

36/55
Solution –Third
Implementation
<
dependencies
>
<
dependency
>
<
groupId
>systems.manifold</
groupId
>
<
artifactId
>manifold-delegation-rt</
artifactId
>
<
version
>${manifold.version}</
version
>
</
dependency
>
</
dependencies
>
<
build
>
<
plugins
>
<
plugin
>
<groupId
>org.apache.maven.plugins</
groupId
>
<
artifactId
>maven-compiler-plugin</
artifactId
>
<
version
>3.13.0</
version
>
<
configuration
>
<
source
>17</
source
>
<
target
>17</
target
>
<
compilerArgs
><
arg
>-Xplugin:Manifold</
arg
></
compilerArgs
>
<
annotationProcessorPaths
>
<
path
>
<
groupId
>systems.manifold</
groupId
>
<
artifactId
>manifold-delegation</
artifactId
>
<
version
>${manifold.version}</
version
>
</
path
>
</
annotationProcessorPaths
>
</
configuration
>
</
plugin
>
Dependency

37/55
Solution –Third
Implementation
<
dependencies
>
<
dependency
>
<
groupId
>systems.manifold</
groupId
>
<
artifactId
>manifold-delegation-rt</
artifactId
>
<
version
>${manifold.version}</
version
>
</
dependency
>
</
dependencies
>
<
build
>
<
plugins
>
<
plugin
>
<groupId
>org.apache.maven.plugins</
groupId
>
<
artifactId
>maven-compiler-plugin</
artifactId
>
<
version
>3.13.0</
version
>
<
configuration
>
<
source
>17</
source
>
<
target
>17</
target
>
<
compilerArgs
><
arg
>-Xplugin:Manifold</
arg
></
compilerArgs
>
<
annotationProcessorPaths
>
<
path
>
<
groupId
>systems.manifold</
groupId
>
<
artifactId
>manifold-delegation</
artifactId
>
<
version
>${manifold.version}</
version
>
</
path
>
</
annotationProcessorPaths
>
</
configuration
>
</
plugin
>
Dependency Plugin

38/55
Solution –Third
Implementation
<
dependencies
>
<
dependency
>
<
groupId
>systems.manifold</
groupId
>
<
artifactId
>manifold-delegation-rt</
artifactId
>
<
version
>${manifold.version}</
version
>
</
dependency
>
</
dependencies
>
<
build
>
<
plugins
>
<
plugin
>
<groupId
>org.apache.maven.plugins</
groupId
>
<
artifactId
>maven-compiler-plugin</
artifactId
>
<
version
>3.13.0</
version
>
<
configuration
>
<
source
>17</
source
>
<
target
>17</
target
>
<
compilerArgs
><
arg
>-Xplugin:Manifold</
arg
></
compilerArgs
>
<
annotationProcessorPaths
>
<
path
>
<
groupId
>systems.manifold</
groupId
>
<
artifactId
>manifold-delegation</
artifactId
>
<
version
>${manifold.version}</
version
>
</
path
>
</
annotationProcessorPaths
>
</
configuration
>
</
plugin
>
Dependency Plugin Annotations

39/55
SUBCLASSING

40/55
Other Problem 
Constructor of inheritable class must never
call overridable method,
why?
public class
SuperClass {
public
SuperClass() {
this
.overrideMe();
}
public void
overrideMe() {
// Some behaviour...
}
}

41/55
Other Problem 
Constructor of inheritable class must never
call overridable method,
why?
public class
SuperClass {
public
SuperClass() {
this
.overrideMe();
}
public void
overrideMe() {
// Some behaviour...
}
}
The constructor calls
an overridable method

42/55
Other Problem –What Happens?
public class
SubClass
extends
SuperClass {
private final
Date
date
;
public
SubClass() {
this
.
date
=
new
Date();
}
@Override public void
overrideMe() {
System.
out
.println(
this
.
date
.toString());
}
}

43/55
Other Problem –What Happens?
NullPointerException
public class
SubClass
extends
SuperClass {
private final
Date
date
;
public
SubClass() {
this
.
date
=
new
Date();
}
@Override public void
overrideMe() {
System.
out
.println(
this
.
date
.toString());
}
}

44/55
Other Problem–Second
Implementation

Constructor of inheritable class must never
call overridable method!
public class
SafeSuperClass {
public
SafeSuperClass() {
this
.cannotOverrideMe();
}
public final void
cannotOverrideMe() {
// Some behaviour...
}
}

45/55
FORWARDING AND
DELEGATION

46/55
Forwarding and
Delegation

“Real-world” example
–12interfaces
–5abstract classes
–21 concrete classes
–Max. depth of
inheritance tree, 5

47/55
Forwarding and Delegation @
org.junit.jupiter.api.
Test
void
testUnexpectedCallToOverridingMethod() {
final
IVertebrate
nyx
=
new
Cat();
Assertions.assertEquals(1,
nyx
.getNumberOfFightMechanisms());
nyx
.addFightingMechanisms(
Arrays.asList(
new
FightMechanismHissing(),
new
FightMechanismTeeth()));
System.
out
.println(
"\nWARNING: All the tests should pass, but this test
actually shows the erroneous behaviour!\n"
);
Assertions.assertEquals(5,
nyx
.getNumberOfFightMechanisms(),
"Received 5 but expected 3, because the method IVertebrate.addFightingMechanism()
is called by IVertebrate.addFightingMechanisms()"
);
}
@
org.junit.jupiter.api.
Test
void
testUnexpectedMissingCallToOverridingMethod() {
final
IBird
echidna1
=
new
Echidna1();
Assertions.assertEquals(20,
echidna1
.layEgg());
final
IBird
echidna2
=
new
Echidna2();
System.
out
.println(
"\nWARNING: All the tests should pass, but this test
actually shows the erroneous behaviour!\n"
);
Assertions.assertEquals(50,
echidna2
.layEgg(),
"Received 50 but expected 20, because the method Echidna2.getEggSize()
is NOT called by AbstractBird.layEgg()"
);
}

48/55
Forwarding and Delegation @
org.junit.jupiter.api.
Test
void
testUnexpectedCallToOverridingMethod() {
final
IVertebrate
nyx
=
new
Cat();
Assertions.assertEquals(1,
nyx
.getNumberOfFightMechanisms());
nyx
.addFightingMechanisms(
Arrays.asList(
new
FightMechanismHissing(),
new
FightMechanismTeeth()));
System.
out
.println(
"\nWARNING: All the tests should pass, but this test
actually shows the erroneous behaviour!\n"
);
Assertions.assertEquals(5,
nyx
.getNumberOfFightMechanisms(),
"Received 5 but expected 3, because the method IVertebrate.addFightingMechanism()
is called by IVertebrate.addFightingMechanisms()"
);
}
@
org.junit.jupiter.api.
Test
void
testUnexpectedMissingCallToOverridingMethod() {
final
IBird
echidna1
=
new
Echidna1();
Assertions.assertEquals(20,
echidna1
.layEgg());
final
IBird
echidna2
=
new
Echidna2();
System.
out
.println(
"\nWARNING: All the tests should pass, but this test
actually shows the erroneous behaviour!\n"
);
Assertions.assertEquals(50,
echidna2
.layEgg(),
"Received 50 but expected 20, because the method Echidna2.getEggSize()
is NOT called by AbstractBird.layEgg()"
);
}
Broken
Forwarding

49/55
Forwarding and Delegation @
org.junit.jupiter.api.
Test
void
testUnexpectedCallToOverridingMethod() {
final
IVertebrate
nyx
=
new
Cat();
Assertions.assertEquals(1,
nyx
.getNumberOfFightMechanisms());
nyx
.addFightingMechanisms(
Arrays.asList(
new
FightMechanismHissing(),
new
FightMechanismTeeth()));
System.
out
.println(
"\nWARNING: All the tests should pass, but this test
actually shows the erroneous behaviour!\n"
);
Assertions.assertEquals(5,
nyx
.getNumberOfFightMechanisms(),
"Received 5 but expected 3, because the method IVertebrate.addFightingMechanism()
is called by IVertebrate.addFightingMechanisms()"
);
}
@
org.junit.jupiter.api.
Test
void
testUnexpectedMissingCallToOverridingMethod() {
final
IBird
echidna1
=
new
Echidna1();
Assertions.assertEquals(20,
echidna1
.layEgg());
final
IBird
echidna2
=
new
Echidna2();
System.
out
.println(
"\nWARNING: All the tests should pass, but this test
actually shows the erroneous behaviour!\n"
);
Assertions.assertEquals(50,
echidna2
.layEgg(),
"Received 50 but expected 20, because the method Echidna2.getEggSize()
is NOT called by AbstractBird.layEgg()"
);
}
Broken
Forwarding
Broken
Delegation

50/55
Forwarding and
Delegation

As of 24/10/01, project Manifold comes with
some constraints on declared types
–Class
AbstractBird
mustimplement
IBird
–Must use
AbstractBird
instead of
Mallard
public class
Echidna2
extends
AbstractMammal
implements
IBird, IMammal {
// For Manifold: must be "AbstractBird
// birdTraits", not "Mallard birdTraits"
@link AbstractBird
birdTraits
=
new
Mallard();

51/55
CONCLUSION

52/55
Conclusion 
Polymorphism is a fundamental concept
of object-oriented programming,but it is
not without problem

Adding one level of indirection solves the
problem
–Encapsulation
–Delegation
Information hiding

53/55
Conclusion 
Encapsulation and delegation

Typing and reflection
Can be used to prevent problem and make
programs more flexible!
Do not require unnecessary, boring, and
error-prone boilerplate code (
Manifold)

54/55
Food For Thoughts 
HashSetdoes not allow duplicate keys so it
could be that super.addAll(c)add less
elements because of some duplicated keys
and, therefore, that this.addCount()
reports more than the really added elements

If we wanted this.addCount()to be also
equal to size...

55/55
Resources 
https://github.com/ptidejteam/tutorials -
ProjectManifold

[email protected]