0

In Java (Android) I had some code which looked like this:

for (Tuple tuple : xRange) {
    Tuple5<Integer, Integer, Double, Double, Double> t = (Tuple5<Integer, Integer, Double, Double, Double>)tuple;
    ...
}

Which can be a pain to write. By the way, Tuple5 derives from Tuple.

So I wrote this method:

@SuppressWarnings("unchecked")
public static final <U1, U2 extends U1> U2 cast(U1 inst) {
    return (U2)inst;
}

Looks nasty, huh? But this then allowed me to rewrite the code like this:

for (Tuple tuple : xRange) {
    Tuple5<Integer, Integer, Double, Double, Double> t = cast(tuple);
    ...
}

I'm compiling on Android using the AIDE compiler. I'm thinking it may not even compile on other systems.

My question is does this work on all compilers? Is it bad code? And, if it is, then why?

Thanks

intrepidis
  • 2,870
  • 1
  • 34
  • 36
  • How is `xRange` declared? – jlordo Aug 11 '13 at 21:12
  • Are you thinking it won't compile on other systems, or is it not compiling on other systems? Those are two very different observations. – Jeffrey Aug 11 '13 at 21:16
  • In most cases that's bad imho. Not worse than the first snippet, though. However, I'd recommend you check if the cast actually can succeed before casting, so you can skip over unsupported collection entries (vs your program crashes on uncasteable entries). – dst Aug 11 '13 at 21:22
  • @Jeffrey: I'm guessing. I don't have any other systems to test on. – intrepidis Aug 11 '13 at 21:24
  • @dst: You mean `if (inst instanceof U1)...`. That sounds good, thanks. – intrepidis Aug 11 '13 at 21:27
  • Actually I've declared xRange as `List xRange`. But in this instance all entries are always the Tuple5. – intrepidis Aug 11 '13 at 21:43
  • @dst: I tried `instanceof`, but the compiler says it's impossible to determine the type at runtime... – intrepidis Aug 11 '13 at 22:04
  • @ChrisNash you can only check if the cast can succeed, not if it will succeed. So you should be able to check if the Tuple is an instance of Tuple5. If instanceof does not work, you can also use reflection (messing with `Class` objects). Note that in any case your code is bad, but maybe not that bad as without it. In an ideal world you do not need such casts :P – dst Aug 11 '13 at 22:24

1 Answers1

1

I think it's bad because of type erasure, it's not an accident that you get a compiler warning (which you suppress).

Your method

public static final <U1, U2> U1 cast(U2 inst) {
    return (U1)inst;
}

looks somewhat like this after type erasure:

public static final Object cast(Object inst) {
    return (Object)inst;
}

so this will not be type-safe, that cast effectively does nothing. You can read more about type erasure here.

Katona
  • 4,816
  • 23
  • 27
  • Thanks. You say it returns Object, but how is this handled at the point of calling? (`t = cast(tuple);`) – intrepidis Aug 11 '13 at 21:58
  • @ChrisNash it will cast as in the first snippet (like `(Tuple5) cast(tuple)`). – dst Aug 11 '13 at 22:22
  • @ChrisNash see [this](http://stackoverflow.com/questions/11353555/what-happens-to-casts-using-generics-tobject-at-run-time-in-java?rq=1) question – Katona Aug 12 '13 at 07:00
  • I have read the question/answer link above and can see that the `cast` method is actually ok. The compiler check is done in the calling code. I have validated this. The `cast` method is a good use of the "suppress unchecked" annotation. Thanks guys! – intrepidis Aug 15 '13 at 11:52