1

I wonder why Java compiler doesn't trust in this line of code :

List<Car> l = new ArrayList();

and expects to have a typed ArrayList :

List<Car> l = new ArrayList<Car>();

Indeed, compiler indicates an unchecked assignment with the first case.

Why doesn't compiler see that this ArrayList() has just been created and so it's impossible to find already in it some objects other than 'Car'?

This warning would make sense if the untyped ArrayList was created before but doesn't in this case ...

Indeed, since List is typed as 'Car', all futures "l.add('object')" will be allowed only if 'object' is a 'Car'. => So, according to me, no surprise could happen.

Am I wrong ?

Thanks

Mik378
  • 21,881
  • 15
  • 82
  • 180
  • 1
    possible duplicate of [What is the point of the diamond operator in Java 7?](http://stackoverflow.com/questions/4166966/what-is-the-point-of-the-diamond-operator-in-java-7) – Thilo Oct 31 '11 at 02:05
  • Indeed, the question is very very similar. I didn't saw it, thanks. – Mik378 Oct 31 '11 at 17:09

2 Answers2

4

Why doesn't compiler see that this ArrayList() has just been created and so it's impossible to find already in it some objects other than 'Car'?

The simple answer is "Because it is not allowed to."

The compiler has to implement the Java Language Specification. If some compiler writer goes and adds a bunch of smarts to the compiler to allow things that "everyone" knows are safe, then what he's actually done is to introduce a portability problem. Code compiled and tested with this compiler will give compilation errors when compiled with a dumb (or more accurately, strictly conformant) Java compiler.

So why doesn't the JLS allow this? I can think of a couple of possible explanations:

  • The JLS writers didn't have time to add this to the specification; e.g. to consider all of the ramifications on the rest of the specification.
  • The JLS writers couldn't figure out a sound way to express this in the specification.
  • The JLS writers didn't want to put something into the specification that they weren't sure was implementable in a real world compiler ... without being too burdensome on the compiler writer.

And then there is the associated question of whether a compiler could implement such a check. I'm not qualified to answer that ... but I know enough about the problem to realize that it is not necessarily as simple to solve as one might imagine.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Well it is obviously possible to implement this (i.e. I could write a preprocessor that "fixes" this problem just by adding the generic), but it certainly complicates the compiler quite a bit. I.e. you at least suddenly need to distinguish where the object comes from or something, because having a raw `LinkedList` that is returned from some arbitrary function, etc. obviously shouldn't have that privilege. – Voo Oct 31 '11 at 02:30
  • I would not recommend using a preprocessor to "fix" this. For a start, it means that your code is not really Java anymore. Re: the compiler complication, that is certainly true. Now imagine having to fold those rules into the Java Language Specification. – Stephen C Oct 31 '11 at 02:32
  • That wasn't my point. I'm just saying if it's easily to be fixed with a preprocessor run, you "could" implement it into the compiler (your last paragraph). Implementing it directly into the compiler is certainly doable, but then it depends on what kind of parser we're using, etc. – Voo Oct 31 '11 at 02:40
  • @Voo - I know enough to know that the kind of parser they are using is not relevant. The checks would need to be done during type analysis or dataflow analysis. – Stephen C Oct 31 '11 at 03:23
  • Yes sadly there's no way to write a simple recursive descent parser that generates the code in one go. Because then it's not much simpler to note in the parser whether the object was generated locally or from some function. There's more than one solution to most problems.. – Voo Oct 31 '11 at 14:33
2

To add to Stephen C's really good answer (mostly because writing this as a comment would be really cumbersome, sorry), this problem is actually explicitly mentioned in the JLS:

Discussion

Variables of a raw type can be assigned from values of any of the type's parametric instances.

For instance, it is possible to assign a Vector<String> to a Vector, based on the subtyping rules (§4.10.2).

The reverse assignment from Vector to Vector<String> is unsafe (since the raw vector might have had a different element type), but is still permitted using unchecked conversion (§5.1.9) in order to enable interfacing with legacy code. In this case, a compiler will issue an unchecked warning.

Why they didn't special case this particular case? Because adding special cases to an implementation isn't something you do if you don't have to and the "correct" solution doesn't add any particular problems (apart from some writing effort which they presumably didn't think was too important).

Also every special case means that the compiler gets more complicated (well generally speaking at least and in this case certainly) - considering how simple javac is on the whole, I'd think it's not unlikely that having a simple, fast compiler was also one of the design goals.

Voo
  • 29,040
  • 11
  • 82
  • 156