Transcript Soso

Helping manage the
concern of object cloning
in Java programs
Eric Bodden
Outline
There’s a lot one can do wrong with cloning
 3+1 heuristics to find code smells
 Eclipse comes to the rescue:

 A way to fix the most frequent smells
Evaluation on Soot
 Conclusion / lessons learned

Problem
Implementations of clone() are often wrong and
inconsistent
 Call (copy) constructors
 throw CloneNotSupportedException
 return null
Also, lots of manual writing of boilerplate code
involved.
Consequence: Cloning often rather avoided,
although conceptually appealing.
Solution
Provide an Eclipse plug-in to…
 detect faulty implementations of cloning
 generate correct implementations.
The general case is hard (impossible?) to solve
but we want to be able to help in most cases.
How should clone() work?
A look at the definition
Creates and returns a copy of this
object. The precise meaning of "copy"
may depend on the class of the object.
The general intent is that, for any
object x, the expression: x.clone() != x
will be true, and that the expression:
x.clone().getClass() == x.getClass()
will be true, but these are not absolute
requirements…
By convention, the returned object
should be obtained by calling
super.clone()…
Code smells… what’s out there?
(or: how Google Code Search made my day)

Looked at Google Code Search; queries:
 lang:java "Object clone()“
 lang:java "Object clone()".*return
 lang:java "Object clone()".*return new

Looked at Soot…
 …and was shocked to find a lot of that going
wrong too
Smell 1: inconsistencies
public class Foo implements Cloneable {
String[] data;
Does not
}
implement clone()
method!
Does not implement
Cloneable interface!
public class Bar {
…
public Object clone() {
…
}
}
Smell 2: returning null
public class Bar {
…
public Object clone() {
return null;
}
}
Returns null!
At least, throw
CloneNotSupportedException instead!
Smell 3: not calling super.clone()
public class Bar {
Baz b;
…
public Object clone() {
return new Bar(b.clone());
}
}
Never calls
super.clone()!
4th checker – more of a style rule
public class Foo {
…
Foo
public Object
clone() {
…
public class Bar {
}
Foo f;
}
…
public Object clone() {
…
clone.f = (Foo) f.clone();
…
}
In Java 5, use
covariant return
type!
}
User interface –
design considerations
tool should be easy to use
 should be applicable to many situations
 should nicely integrate within Eclipse

 consistent look and feel

reuse as much functionality as possible from
the Java Development Toolkit
 unfortunately implies the use of internal APIs 
Using the tool
Parameters
Fields selected for
deep copy
Optimal usage mode

Applying the tool to a large existing code
base is a little tedious
 No way of automated refactoring
Hence, should be used from the beginning
 When applying to multiple classes, start at
the bottom of the hierarchy!

Case study – Cloning in Soot
Statements and expressions are often
copied, e.g. for inlining etc.
 Currently not consistently implemented

Hence: Apply heuristics and implement
cloning correctly.
Heuristics on Soot
Complete
240 clone() methods
Consistent class
annotation
189 classes do not
implement interface
14 do not implement
clone() method
Returning null
No violations
Not calling super.clone() 237 violations!
Object as return type
In all 240 cases
Modifications on Soot
179 clone() methods could be removed!
 37 replaced by standard implementations
 16 replaced by non-standard impl.

 Null-pointer checks
 Necessary deep copying of arrays or lists
1 deliberate case of “return this” (constants)
 3 times clone() added to interface
 11 times replaced abstract method by
concrete implementation

Modifications on Soot
public class Foo implements
Cloneable {
public abstract Object clone();
…
}
public class Bar extends Foo {
public Object clone() {
Bar clone = super.clone();
…
return clone;
}
}
Modifications on Soot
Had to add another 26 default
implementations to make it complete
 Plus two non-default ones
 In seven cases we converted the return type
 In 11 cases we kept the original
implementation of clone (e.g. JimpleBody)

 Used SuppressWarnings (does not work yet )
Results summary
Refactoring eliminated more than half of the
clone() methods
 Saved 628 lines of code (about 1/3 of the
implementation)
 Eliminated at least one bug. (“return field;”)

Related work
Generation of equals/hashCode methods
 Work on return code idiom (Bruntink et al.)
 Mixins, Traits, Virtual Classes
 Dehua Zhang (automatic generation of
clone() methods)

Contributions
Thorough evaluation of the concern of
cloning data objects in a non-trivial software
system
 Provided a tool to detect code smells with
respect to cloning
 Provided a tool to implement cloning more
consistently
 Showed that application of the tool actually
helps make the concern more manageable

Conclusion





Copy constructors are bad style and add a lot of
unnecessary code.
Tool support can help generate consistent clone()
methods
Detecting faulty implementations is surprisingly
easy
… and so is generating correct ones in most cases.
Covariant return types can avoid errors and help
keep code concise.