7 ms·
JVM Anatomy Quarks
- quotemstr 2y agohttps://shipilev.net/jvm/anatomy-quarks/17-trust-nonstatic-final-fields/ https://shipilev.net/jvm/anatomy-quarks/17-trust-nonstatic-f... is a damned shame. User code misses out on an important optimization available only to system-provided classes because certain frameworks have abused JNI and reflection to mutate final fields, which by all rights should be immutable. Platforms, especially compilers and runtimes, need to be absolutely strict in enforcing semantic restrictions so as to preserve optimization opportunities for the future.
- J-Kuhn 2y agoYes, but you would be surprised how many people want to change static final fields for various reasons - be it testing, or other things. When telling those that it doesn't work, and that it can not work without violating the semantics of the JVM, they will wave their hand and say "look, it does work here". And it looks like, yes, if the stars align in that specific constellation, it may work.
- deleted 2y ago[deleted]
- hinkley 2y agoAlso a part of why Singletons are the black sheep of the Patterns family. They’re nasty during bootstrapping and hell during functional testing.
- bobnamob 2y agoI’ll be the first to admit that I’ve written the evil three liner to “un-final”, mutate, re-final a member off in some long forgotten internal library to dodge a gnarly refactor. I do wish that I couldn’t have done so, shrug, business needs
- blibble 2y agothe System.out thing is Java itself https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.4 https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.htm... given this it's not surprising others thought it was acceptable also
- deepsun 2y agoI wonder if it thanks to some people blindly following Effective Java book that made a sin by saying "final all the things". So now we cannot easily mock final classes in tests. And mocking tools have to resort to bytecode manipulation to mock the final classes. E.g. Effective Java is a requirement inside Google, so even public GDrive APIs have final classes. External APIs is exactly the thing you'd want to mock.
- lupire 2y agoIf you are rigorous as to make classes final, you should also be rigorous to never provide a non-interface as an Application Programming Interface. Google uses mocks and fakes implementations of interfaces, and provides dependency injection frameworks for managing these (Guice and Dagger).
- stickfigure 2y agoI once worked with a guy who obsessively made interfaces for every java class. Even domain objects. He was extremely proud of this. It was garbage.
- redditor98654 2y agoWas this in Amazon? If so, it might have been me. Sorry about that. I have learnt my lesson now. I don’t recall doing it for domain objects though.
- adamnew123456 2y agoI would say less overuse of final, more underuse of interfaces. If everything takes/returns/stores values by interfaces (excluding data containers with no behavior) then you don't need to "jailbreak" any class to mock it. Of course you get code bloat defining interfaces for everything you intend to implement once, and you have to enforce these rules, but this is something that could be made easier. Not in Java, but imagine a language where: - Concrete classes can only be used in new, or in some platform provided DI container. - Methods can only accept interface types and return interface types. - Fields are private only, all public/protected is via properties (or getters/setters, it just has to be declarable in an interface) - You have a ".interface" syntax (akin to ".class" but for types) that refers to the public members of a class without tying you to the concrete class itself. You can use this as a shorthand instead of declaring separate interfaces for everything. Eg. ``` final class GDrive { ... } public Download file(GDrive.interface drive) { ... } class MockDrive implements GDrive.interface { ... } ``` The closest I can think of is a hypothetical typed variant of NewSpeak, but maybe something like this exists already?
- rusk 2y agoField modifiers are a semantic constraint not a security constraint. It is right and proper that you should be able to bypass them with the appropriate backflips. The main issue is safety cause you might modify something that isn’t modifiable and cause a SEGV and that is precisely the concern access modifiers are meant to address.
- blibble 2y agothey certainly were a security constraint back in the day before Java gave up on trying to use the type system for security e.g. SecurityManager for applets will not let you setAccessible(true) on private fields of system classes
- rusk 2y agoYes but that’s the security manager doing it not the field modifiers. It’s just reusing the modifiers as security metadata.
- elric 2y agoIIRC illegal access can be locked down and be controlled in a fine grained manner with the add-opens and illegal-access flags on newer JVMs.
- pron 2y agoAs part of our "integrity by default" strategy [1] we're changing that. There will be a JEP about it soon. The idea is that because not much code actually needs to mutate finals (and even if it does, that operation is already limited today to classes in the code's own modules or ones explicitly "open" to it), the application will need to grant a permission to a module that wants to mutate finals, similar to how we've recently done things with native calls and unsafe memory access. [1]: https://openjdk.org/jeps/8305968 https://openjdk.org/jeps/8305968
- exabrial 2y agoI love the "size" of these posts. Kinda neat to just read through one in a few mins and maybe run the bench locally.
- azinman2 2y agoI’ve basically forgotten about Java. It would never occur to me to start a new project in it. Am I the only one? It feels like I’d reach for python if I want fast development and flexibility, Go if I want to handle a bunch of I/O concurrency in a garbage collected way, Swift if I want a nice language that’s compiled and balanced, or Rust if I want performance and safety in a compiled language. Those are just my personal leanings. I know kotlin has made Java more ergonomic, and yet….
- kaba0 2y agoFlamewar-y reply to a flamewar-y comment: Java is better than Go on every count, and almost all of your cases are 90% done by Java, so it's quite clearly a very good choice for almost everything.
- mpenet 2y agoThere are plenty of very ergonomic languages on the JVM (for instance clojure). I wouldn’t dismiss the JVM as a whole, it is a marvel of engineering and is evolving quickly nowadays (see loom, panama, leyden, etc…).
- pianoben 2y agoI think it's not just you, but certainly not everyone. Kotlin with Java 21+ is my go-to choice for an I/O-bound service, or really any service. It's just so ergonomic, and with virtual threads the code can be as simple and efficient as Go - while also taking advantage of possibly the best and largest library ecosystem in the world. I'm not knocking Go or Python - if those are your preferred tools, they're more than adequate. Java, however, isn't nearly as irrelevant as you may perceive.
- lsuresh 2y agoHappy to see this gem shared here. I've learnt a lot about the JVM going through these. This article about the "stack allocation" misnomer in Java in particular is one of my favorites: https://shipilev.net/jvm/anatomy-quarks/18-scalar-replacement/ https://shipilev.net/jvm/anatomy-quarks/18-scalar-replacemen.... What the JVM really does is escape analysis + scalar replacement.
- deleted 2y ago[deleted]
- lukeh 2y agoTangential: Apple has a new Swift Java bridge which is pretty cool, supporting both JNI and Panama. I’ve been porting it to Android this past week. https://github.com/swiftlang/swift-java https://github.com/swiftlang/swift-java
- palata 2y agoI find the "modern" (if I can call it that) approach to cross-platform interesting: interoperability between languages makes it possible to share a library between multiple platforms when it makes sense. Until now I was exclusively doing that with C++ (possibly with a C API), but obviously C++ is never the preferred language when it is itself not necessary. My concern, however, is about the cost of doing this. Say I have an easy way to call my Kotlin library from Swift in a mobile app, doesn't it mean that now my iOS app will load some kind of JVM (I don't know what would run on iOS)? Similarly, if I could call Swift from an Android app, wouldn't it load some kind of Swift runtime? It all brings overhead, right? I guess I fear that someday, developers will routinely depend on e.g. a Swift library, that will depend on a Kotlin library (loading some JVM), that will itself use JNI to call some C++. Just like with modern package managers, programs quickly end up having 100+ transitive dependencies (even with just a few direct dependencies) just because it was "too easy" for the developer not to care.
- plandis 2y agoIf you work for a few years with JVM based languages this set of articles are so interesting! I remember reading through these for the first time several years ago.
- wging 2y agoDoes anyone know why the name of this series was changed from ‘JVM Anatomy Park’?
- aardvark179 2y agoI think he renamed it when stuff first started coming out about Justin Rolland’s online behaviour.
- deleted 2y ago[deleted]