Helping manage theconcern of object
cloningin 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 definitionCreates 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()".*returnlang: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!
public class Bar {
…
public Object clone() {
…
}
}
Does not implement Cloneable interface!
public class Bar {
…
public Object clone() {
return null;
}
}
Smell 2: returning null
Returns null!
At least, throw CloneNotSupportedException instead!
public class Bar {
Baz b;
…
public Object clone() {
return new Bar(b.clone());
}
}
Smell 3: not calling super.clone()
Never calls super.clone()!
public class Foo {
…
public Object clone() {
…
}
}
4th checker – more of a style rule
Foo
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 Toolkitunfortunately implies the use of internal APIs
Using the tool
ParametersFields selected for
deep copy
Optimal usage mode
Applying the tool to a large existing code base is a little tediousNo 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 SootComplete 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 checksNecessary 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
public class Foo implements Cloneable {
public abstract Object clone();
…
}
Modifications on Soot
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.
Top Related