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.