Does not implement clone() method! public class Bar { … public Object clone() { … } Does not...

23
Helping manage the concern of object cloning in Java programs Eric Bodden

Transcript of Does not implement clone() method! public class Bar { … public Object clone() { … } Does not...

Page 1: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

Helping manage theconcern of object

cloningin Java programs

Eric Bodden

Page 2: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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

Page 3: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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.

Page 4: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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.

Page 5: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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()…

Page 6: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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

Page 7: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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!

Page 8: 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!

Page 9: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

public class Bar {

Baz b;

public Object clone() {

return new Bar(b.clone());

}

}

Smell 3: not calling super.clone()

Never calls super.clone()!

Page 10: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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!

Page 11: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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

Page 12: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

Using the tool

Page 13: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

ParametersFields selected for

deep copy

Page 14: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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!

Page 15: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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.

Page 16: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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

Page 17: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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

Page 18: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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;

}

}

Page 19: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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 )

Page 20: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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;”)

Page 21: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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)

Page 22: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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

Page 23: Does not implement clone() method! public class Bar { … public Object clone() { … } Does not implement Cloneable interface!

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.