13

My IDE (NetBeans) type checks my Collections while I am typing code. But then, why do I have to cast the returned object of Object.clone()? Which is fine. No harm no foul. But still, I don't understand.

Is type checking, without casting, the returned object of Object.clone() not possible? The generics framework makes me think the IDE could check the type of object references on the right-side of the "=" mark without casting while I am typing? I don't get it.

addendum
My usage case was just that I had a private Calendar field, pubdate. I was going to write:

Calendar getPubdate() {
    return pubdate;
}

but there is a risk that the invoker could modify my pubdate, so I returned a copy:

Calendar getPubdate() {
    return (Calendar) pubdate.clone();
}

Then, I wondered why I needed to cast pubdate.clone(). The method signature has the type right there. NetBeans should be able to figure that one out. And NetBeans seemed to be doing something similar with regard to Collections.

konishiki
  • 475
  • 3
  • 10
  • 5
    A short (!) code example would be helpful. – Doc Brown Mar 15 '16 at 11:41
  • 78
    The IDE is separate from the language itself, so how smart Netbeans is have no effect on how Java the language works. – JacquesB Mar 15 '16 at 11:47
  • 7
    Note, due to return type covariance, it is recommended to return `MyObject` from `clone()` rather than `Object` - this removes this entire issue. It is further recommended never to use `clone()` (Effective Java Item #11). – Boris the Spider Mar 15 '16 at 14:28
  • Is the emphasis of your question on ***I*** or on *'cast "clone()"'*? Because the question resulting from the former might actually be a much better question than from the latter. – user541686 Mar 16 '16 at 10:56
  • When I read the question title, the only thing I think of is `this.clone()` on programmer object, especially at Wed's night after Tue's release. Sorry but I have to write this comment..Why can't smart IDE just fixes all bugs for us LOL – Patrick the Cat Mar 16 '16 at 12:31
  • Seems like in many cases the IDE could at least automatically add the casting. – Brian Risk Mar 16 '16 at 13:07
  • @Mehrdad I added an addendum to explain what happened. I'd never really heard of "type inference" before. very useful. – konishiki Mar 16 '16 at 14:48
  • The Cloneable interface is generally avoided, largely because of the need to handle CloneNotSupportedException. Consider using a copy constructor "public X(X old)" or a static method "public static X copy(X old)". – kevin cline Mar 16 '16 at 16:40
  • @kevincline While cloning is generally bad, what about the `Calendar` class in specific? It is a base class so I'm sure it meets the definition of Object.clone(). Since I know `CloneNotSupported` will never be thrown by `Calendar`, I'd think cloning is ok in this case. It is so convenient as well. – konishiki Mar 16 '16 at 18:26
  • If you are using java.util.Calendar, stop immediately and switch to the new classes in the java.time package. The java.util time and date classes are perfectly designed to engender the maximum number of bugs in application code. – kevin cline Mar 16 '16 at 21:47

4 Answers4

54

why do I have to cast the returned object of Object.clone()?

Because it returns Object.

The generics framework makes me think the IDE could check the type of object references on the right-side of the "=" mark without casting while I am typing? I don't get it.

Object.clone is not generic.

If generics had existed when clone was designed, it probably would have looked like this (using F-Bounded Polymorphism):

interface Cloneable<T extends Cloneable<T>> {
  T clone();
}

If Java had a MyType feature, it would maybe look like this:

interface Cloneable {
  this clone();
}

But Generics didn't exist when Object.clone was designed, and Java doesn't have MyTypes, so the type-unsafe version of Object.clone is what we have to work with.

Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318
  • I just realized that the IDE feature that confused me was background compilation? I mean, that is what enables code completion and auto type checking with generics? Personally, I'd prefer delaying type checking until an explicit compile. But I do love code completion. – konishiki Mar 15 '16 at 14:17
  • 1
    @konishiki with Java 8 (and to some extent Java 7) type _inference_, in order to provide any assistance, the IDE needs to infer types. This requires partial compilation. Before type inference, no compilation is needed for autocompletion. – Boris the Spider Mar 15 '16 at 14:25
  • @BoristheSpider Thanks so much for that feedback! I definitely need to do some more testing / thinking. very much appreciated. – konishiki Mar 15 '16 at 14:33
  • Why would you need to pass `original`? – Clashsoft Mar 15 '16 at 20:22
  • @Clashsoft: Stupid thinko while adapting the obvious Functional Programming version. Thanks. – Jörg W Mittag Mar 15 '16 at 21:24
  • Note that Java 8 supports this functional notation style (explicitly listing the method receiver as parameter), but the syntax is slightly different to what you wrote: `interface Cloneable> { T clone(Cloneable this); }`, so can’t name it “`original`” but still have to access it as “`this`”. The rationale behind this feature is to allow type annotations for the receiver type. Regarding the return type, there are a few exceptions where a relation to the receiver type is possible, invoking `clone()` on an array type returns the array type and there’s `Object#getClass()`… – Holger Mar 16 '16 at 09:57
  • @Holger: Ah, I was so excited when I read your comment that Java has `this` type annotations, until I realized that "Type Annotation" in Java means something completely different from all other languages :-D For anyone wondering: this is called an "explicit receiver parameter" and it cannot do any of the cool things that self type annotations can do in languages like Scala, for example. It's just a syntactic thing, similar to Python, it has no semantic meaning. But don't despair: I actually *did* find discussions about possibly expanding its semantics in future versions of Java (10+). – Jörg W Mittag Mar 16 '16 at 10:36
  • In case you are wondering what I am referring to with my "annotation" comment: in pretty much all languages, "type annotation" means "annotating something with a type", but in Java, it means "annotating a type with something". – Jörg W Mittag Mar 16 '16 at 10:38
  • @Jörg W Mittag: these annotations *can* carry semantic meaning, but the ordinary compiler like `javac` will ignore it. Someone has to implement an annotation or byte code processor implementing the semantics. And since annotations are types you can annotate a type with a type, but yeah, even ”types” have different meaning in different programming languages… – Holger Mar 16 '16 at 10:41
  • @JörgWMittag: I don't even think it's a question of whether advanced generics exist, it's a question of inheritance. Even if you have the generics that you mentioned then inheritance will still require you to re-implement a different instantiation of the `Cloneable` interface in order to get a sane signature which doesn't make a whole lot of conceptual sense... – user541686 Mar 16 '16 at 10:59
26

This is not a feature of any IDE, but of the language definition.

An IDE helps you use a programming language more efficiently, it doesn't change the semantics of that language. That means that an editor helper might automatically insert a cast when it's obvious which one you want, but it can't simply break the rules of the language and pretend that code that doesn't compile is valid.

Edit It's true that an IDE can bundle its own compiler, and in fact many do exactly that, e.g. for better error reporting with more inside information into the partial parse tree. However, it would be a very bad idea to let this internal compiler implement different language semantics than the official SDK, since that would mean that code that works in development can mysteriously start failing when installed in production - producing problems that are by definition un-debuggable!

Kilian Foth
  • 107,706
  • 45
  • 295
  • 310
  • This is what happened: I'm pretty sure code completion is an IDE feature (done via reflection). And the auto type checking I was talking about happens in the IDE (via background compilation). I hope that is what is going on. – konishiki Mar 15 '16 at 12:38
  • 1
    The IDE *can* very easily break all the rules of the language spec and just compile the code anyways. I know both NetBeans and Eclipse use their own compilers, for example. So in those cases IDE and compiler are effectively the same thing. Not saying it's a good idea, but C compilers certainly do it all the time. – MichaelS Mar 15 '16 at 13:34
  • @MichaelS The C language specification is designed to allow significant variation between implementations, so that different vendors can choose between different possible approaches and add extra features. This creates various areas of ambiguity in the specification, which are necessary to allow those variations. The name "C" is not trademarked, so nobody controls the use of the term. The Java specification is designed to eliminate as much ambiguity as possible, and Java is trademarked and the trademark holder enforces that it can only be used in compliant implementations. – Jules Mar 15 '16 at 20:20
  • Modern IDE's need a compiler anyway. Code completion hints require that the code before the cursor is parsed. And certainly with generics (or C++ templates) that requires a full compiler, not just a parser. – MSalters Mar 16 '16 at 11:35
3

It is due to the type signature of the Object.clone method. The type signature states that the method will return an object of type Object.

protected Object clone() throws CloneNotSupportedException

The collections will use so called generic types to substitute the type of casting automatically.

So if you have this code:

List<Integer> ints = Arrays.asList(1,2,3);
int x = ints.get(0);`

the compiler will add the casts for you behind the scenes, so the code would actually be:

List ints = Arrays.asList(1,2,3);
int x = (Integer)ints.get(0);
Lightness Races in Orbit
  • 8,755
  • 3
  • 41
  • 45
Miro
  • 39
  • 2
0

For completeness, since Java 5, covariant return types are allowed. So you can write the following:

public MyObject implements Cloneable {
  @Override
  public MyObject clone() {
    try {
      return (MyObject)super.clone();
    } catch (CloneNotSupportedException e) {
      throw new AssertionError();
    }
  }
}

With this, the following code is legal:

MyObject original = new MyObject();
MyObject clone = original.clone();