Interesting proposals: Java 9 and beyond

Thirdly, the diamond operator was previously invalid syntax, not just invalid code? I think some of the Project Coin proposals were rejected on that basis.

Project Coin had a similar proposal to JEP 286 which used final. In some ways that makes a lot more sense to me - if you want a variable you can assign to later you should be explicit about the type.

Only one thing about type inference done too far: Haskell
Everything is totally type-safe (for the compiler) but absolutely not readable for a human.
Why? Because humans are not compilers and a human simply wants a type annotation every now and then to know what he/she is dealing with, instead of having to manually type-infer the whole program in his head (or hover over some text in some IDE to see what type it is).

I think Cas means this:


String x = (String) thing.foo();
String x = thing.foo();

If the compiler cannot figure out line 1 would result in a cast-exception at runtime, then removing the cast certainly won’t move a compile-time error to a runtime error.

If the compiler can figure out line 1 would result in a cast-exception at runtime, then removing the cast certainly won’t move a compile-time error to a runtime error, because the compiler knows this cast has to be done, and therefore will do the cast check on line 2.

The thing is if the compiler can figure out that the explicit cast in line 1 would result in a cast-exception at runtime, then it would disallow the cast alltogether, because casting would not make any sense and would always result in an error.
Or maybe I did not get you.

Isn’t widespread use of instanceof seen as an anti-pattern?

https://www.google.com.au/search?q=instanceof+antipattern

And as @KaiHH says, this has nothing to do with what the compiler can figure out and everything to do with what a human can figure out! Looking at that code, line 2 tells me that thing.foo() always returns a String, line 1 says it might not. These are semantically different. I think the number of people who’ll code that pattern by mistake will outnumber the number who want it!

instanceof is a sign of code-smell on one hand, but like unstructured gotos in C is a lifesaver is some cases as well. So it goes. (polymorphic call-site with high probability of a given target).

If I write


String x = (String) thing.foo();

then I am already asserting that thing.foo() always returns a String even it it is declared to return an Object (remember - ClassCastExceptions are exceptions - no normal program flow should ever explicitly rely on exceptions!)

As x can only ever contain a String, why do I need to assert it twice?

Cas :slight_smile:

You’re asserting it for certain circumstances / certain state of your project. If that’s always the case and thing.foo() is your code, rewrite thing.foo()! Otherwise, that’s not the same assertion.

My point is really the opposite - in line 2 you’re not asserting anything. It’s equally likely that people write that code as a mistake. Now, the compiler will flag that as an error.

I’m generally of the opinion that single use of instanceof or casting (eg. not a chain of if statements) is fine on occasion and better than the convoluted crap people sometimes write just because they’ve heard they shouldn’t use it! :persecutioncomplex: It’s a useful workaround to Java not having double dispatch.

I also agree with @nsigma.
I can only think of one reason why an explicit cast is necessary here: To pat the programmer on the back of his hand and saying “You need a cast here? Probably your class model/data structure is not right.”
Whenever you need to cast, it is (mostly) bad. Be it implicit or explicit. I think it is meant to hint the programmer to that.
Doing an explicit cast then makes the compiler step out of the way by saying: “But I warned you!”

With this it’d be extremely easy to accidentally cast something without the intention of doing so, and there’s no warning or indicator of it happening. I’m against this for the same reason I’m against var: it obfuscates the code needlessly.

Actually, while you’re correct, I think the attention should go to this:


String var = (String) object.foo();

// versus

String var = (String) object.foo().bar();


As you can see, the first one is just the normal cast, but the second one is an extended cast, where bar would return an object. The left hand and right hand operands are completely seperate. String var; is the accessor of the object.

I have no idea what point you’re trying to make here. Those two are completely different things, where at the end you cast the result to a String.

Examples of things that can go wrong with implicit casting:

  • [icode]int anInt = aFloat;[/icode] Accidental rounding, JGO would be flooded with “why is my aspect ratio wrong? [icode]float aspect = width/height;[/icode]”-like problems.
  • Overloaded functions would completely break in many applications because most things can be cast to most things all of a sudden.
  • You could easily get away with an ArrayList without any generics and nobody would know what the list is used for.

I for one am in favour of forcing people to be clear with their intentions, especially when the cost is to type “int” instead of “var” in front of variable declarations, or having to cast variables so you at least feel a bit guilty for doing it instead of being able to pretend that everything’s fine.

The only thing time implicit casts would be okay would be inside an if(instanceof)-block. Frankly, why not just update the type of the object tested if it can be proven to be that type within a block?


if(x instanceof String){
    //Inside here x is a String.
}

Try reading the example I posted earlier and the link to the Project Coin mailing list archives. One reason your suggestion was rejected relates to overloaded methods -



void doSomething(Object s) {}

void doSomething(String s) {}

//

if (x instanceof String) {
    //Inside here x is a String.
  doSomething(x); // oops, we've changed behaviour!
}

You can’t compare primitive conversion with type narrowing as they are totally different priniciples. Primitive conversion actually changes the representation of the data. Type narrowing is simply an assertion for the compiler.

Again I ask you:

What extra do you bring to the table when you do:


String var = (String) object.foo();

over


String var = object.foo();

that is not both explicit and implicit already in the code?

Remember an illegal cast is still an illegal cast: if foo() returns an Integer it cannot be cast to String and the compiler will reject the code. If foo() returns any supertype of String (only Object in this case) then why must I write String twice? C’mon, you’re not making clear what this “potential confusion” could possibly be.

Cas :slight_smile:

You actually got my point: it doesn’t change anything, because the compiler can infer everything already, and already does so - which means it’s a compile-time error. The new syntax won’t trade off compile-time errors for runtime-errors.

Note that I’m not actually in favor of the above (it certainly is a sign of code smell) - I’m just defending the point that it does not change anything.

@Cas

Most likely the only one who knows that object.foo() always returns a String despite being declared Object is the person who wrote the code. The entire thing is easily solved by extending the class and overriding the function to explicitly return String. If you choose not to do that and hack around it, I WANT TO KNOW THAT. Any time you need to cast like that it implies that there’s lots of obfuscated information the programmer didn’t explicitly code in about how the program works and the data is used. To answer your question, the information that is lost is that object.foo() actually returns a value other than String, but you’re casting it to that. That’s not clear without knowing how foo() works in the first place.

very interesting! thank you very much :slight_smile:

wait … did I just read about primitive generics ?

Wow, very nice argument! Thanks!

I’m pretty sure the callsite also knows that it always returns a String, because that’s what the code asserts. Twice.

Cas :slight_smile: