5 ms·
I'd classify this one under: So what? If you beat your tools hard enough, something will give. The simple solution is to stop abusing your tools. Generics w
by hyperman1 5y ago
I'd classify this one under: So what? If you beat your tools hard enough, something will give. The simple solution is to stop abusing your tools.
Generics were bolted on in Java 5, and some painful compromises had to be made to have both backward compatibility and generics. The whole type erasure thing being the prime example.
There is some kind of heap corruption in that you can force a Duck in a list of Cars. But the very first time you try to use that Duck as a Car, the JVM will catch it and hit you with an exception. You won't get C-like undefined behavior this way.
Java had some painfull bugs with real world consequences. This is not one of them.
Now if you want to really abuse Java, try this one :
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
field.set(1, 666);
List<Integer> list = Arrays.asList(1, 2, 3);
System.out.println(list); //prints [666,2,3]
and java allows half of the number 1s in your program to magically change into a 666. Total mayhem ensues. Solution: Don't do this.
- hashmash 5y agoThe Java module system doesn't allow this trick to work anymore. java.lang.reflect.InaccessibleObjectException: Unable to make field private final int java.lang.Integer.value accessible: module java.base does not "opens java.lang" to unnamed module
- _old_dude_ 5y agoThis trick does not work with Java 11+, you can not peek and poke the JDK internals anymore. It's the reason why the transition from Java 8 to 11 has been painful.
- kasperni 5y ago> Now if you want to really abuse Java, try this one : This is no longer possible out of the box after "JEP 403: Strongly Encapsulate JDK Internals" [1]. [1] https://openjdk.java.net/jeps/403 https://openjdk.java.net/jeps/403
- hyperman1 5y agoThat will teach me to test on Java 8. Oh well. The whole point was it was a bad idea. UPDATE: I see there is a flag --illegal-access=permit so if you want to abuse Java, you can still go ahead ;-)
- hashmash 5y agoOpenJDK 64-Bit Server VM warning: Ignoring option --illegal-access=permit; support was removed in 17.0
- hyperman1 5y agoDamn you guys/girls are fast.
- dpratt 5y agoAs of Java 17, no longer. This option was intended as a migration path for badly behaving code, and as of today it no longer works.
- kasperni 5y agoSupport for --illegal-access=permit was removed with Java 17. But you can use "--add-opens=java.base/java.lang=ALL-UNNAMED" instead if you really want. If you really want to shoot yourself in the foot. You can always go native...
- shagie 5y agoThe tinkering with the Integer cache to make 2 + 2 = 5 : https://codegolf.stackexchange.com/a/28818 https://codegolf.stackexchange.com/a/28818 The trick is to make the int literal to get boxed so that it hits the cache - which requires a printf (rather than println). And yea, don't do this.
- Turing_Machine 5y agoThere was an old-time "hacker test", one of the questions of which was "Ever change the value of 4? In a language other than FORTRAN?" So I guess the answer here would be "yes" to both parts. Well done!
- MaxBarraclough 5y agoAs an occasional dabbler in Forth, I can answer in the affirmative. Well, I'm not sure I redefined 4 specifically, but I tried out redefining a few integer literals.
- pulse7 5y agoIn Smalltalk you could write "Smalltalk become: nil" which would replace all references from Smalltalk (global variable holding the whole Smalltalk) to nil. VM would crash instantly... But who cared? Developer had power to do all this...
- rbanffy 5y agoI did that once with `True := False` or something equally stupid. Of course it worked and the machine froze instantly.
- mumblemumble 5y agoType erasure gets blamed for too much. Want to see some languages that make generics sing? Take a look at SML, Haskell, or Rust. What's another interesting characteristic that unites them? They erase all types. Not just generic type parameters like Java does. Everything is type erased. And they do just fine. I would argue that the real problem with Java's rollout of generics is at the language level. The language itself introduced some strange gaps in the semantics of generics, such as failing to build any decent bridges between arrays and generic collections. I don't know that this was necessary. Scala and Kotlin are working out OK, and they have unified arrays with generics. And the other problem is that generic types are not exactly first-class types in Java, even before type erasure takes place. This means handling some key use cases for generics requires resorting to the "super type token" pattern, which is awkward and still not all that well known. I don't think I'm alone in this sentiment. Coders at Work has an interview with a developer who worked on Java 5, and he also expresses a belief that, in retrospect, the problem with Java generics wasn't type erasure, it's that they rushed the feature and some of the language-level design characteristics weren't fully baked yet. (He didn't go much into specifics, though, so I can't say if our opinions agree in the specifics.)
- messe 5y agoI was under the impression that Rust uses monomorphization, not type erasure in its implementation of generics? (Although it does have a form of type-erasure in &dyn Trait objects)
- mumblemumble 5y agoIt monomorphizes generic functions and methods. Type erasure happens to the actual values. So, for example, at run time an Option<i32> ends up just storing one word for indicating whether it's Some or None, and another for the value when it's Some, but doesn't store any information to indicate that those 8 bytes represent an Option<T> of any kind, let alone exactly what kind of value is being stored in it. None of that is needed at run time, because the compiler was able to statically verify that no function is going to try to read them as a u64 instead.
- ARandumGuy 5y agoExactly. Every programming language out there has some cases where you can break the established rules by doing weird stuff. When this sort of thing happens, there's two things to look at: 1) Is this likely to happen by accident? 2) Does this enable some functionality not otherwise available (even if it's still a bad idea) Looking at the paper, it seems like neither of these is the case for Java/Scala types. Given that, I would categorize this as a weird quirk of Java and Scala, and leave it at that.
- Gunax 5y agoI dont think this has to be true. We shouod be able to build perfectly logical and deterministic type systems--and ny understanding is that Java was unambiguous before generics were added.
- hyperman1 5y agoI'd guess ARandumGuy has the soul of an engineer. Confronted with an imperfection, the question is how bad it is in a world full of even bigger imperfections. Is it worth the time,effort and resources to fix it? Gunax has the soul of a mathematician. Confronted with an imperfection, the question is how to eradicate this blight from the world and get us one step closer to perfection, no matter the cost. Both are equally correct reactions, of course. Just nice to see them in the same place.
- AnimalMuppet 5y agoUm, why does this only change half the number 1s in your program?
- shagie 5y agoThat use (and I haven't checked it - see my other post in this thread which I know works ( http://ideone.com/o1h0hR http://ideone.com/o1h0hR ) involves the boxing of an int literal to an Integer. In making it into a List<Integer>, it goes through boxing. https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html https://docs.oracle.com/javase/tutorial/java/data/autoboxing... The "half" means that this doesn't impact things like "int foo = 1 + 1" which will be 2 rather than 1,332. It's not because it's half of the uses of 1, but rather that some portion of the code will be converting int to Integer and that will impact those uses.