top | item 42100876

JVM Anatomy Quarks

230 points| lichtenberger | 1 year ago |shipilev.net

85 comments

order

quotemstr|1 year ago

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.

pron|1 year ago

As 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

deepsun|1 year ago

I 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.

rusk|1 year ago

Field 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.

bobnamob|1 year ago

I’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

J-Kuhn|1 year ago

Yes, 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.

elric|1 year ago

IIRC 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.

lukeh|1 year ago

Tangential: 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

palata|1 year ago

I 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.

exabrial|1 year ago

I love the "size" of these posts. Kinda neat to just read through one in a few mins and maybe run the bench locally.

plandis|1 year ago

If 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|1 year ago

Does anyone know why the name of this series was changed from ‘JVM Anatomy Park’?

aardvark179|1 year ago

I think he renamed it when stuff first started coming out about Justin Rolland’s online behaviour.

azinman2|1 year ago

I’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….

dcminter|1 year ago

You're not the only one I'm sure, but sounds like you don't need it. Its major strengths are:

• Bottomless resource of developers with Java experience

• Vast array of existing libraries many of which are enterprise focused

• Managing very large codebases with many contributors is straightforward

• Standard VM that's very solid (decades of development), reasonably fast, and supported on essentially all platforms.

It doesn't have quite the stranglehold (even in Enterprise) that it had in perhaps the early 2000s and it's the archetypical "blub" language, but it's a perfectly reasonable language to choose if you're expecting Enterprise scale and pure performance is less valuable to you than scaling out with large numbers of developers.

I like Rust, but it's Java that puts bread on my table.

ivan_gammel|1 year ago

In addition to other answers: Java absolutely does have the qualities necessary for startups, so using it for new projects makes sense.

1. Modern frameworks and AI assistance can help ramping up a decent backend in days. Solo tech co-founder needs to know only Java or Kotlin and some frontend stack to build MVP quickly and will spend such amount of time on non-coding tasks where language features will be irrelevant. Swift can be the second language if you go mobile-native.

2. Scaling isn’t the problem you are going to have for quite a while. It is quite likely, that problem of scaling the team will come first and any performance bottlenecks will be noticeable much later. Java is good for large teams.

That said, from business perspective, if you want larger talent pool, fast delivery cycles and something that may remain as your core stack in the long term - Java or Kotlin is probably the best choice. If you want fancy tech as a perk to attract certain cohort of developers or you have that rare business case, you can choose Go or Rust. Python is popular in academia and bootcamps, but TBH I struggle to see the business value of it for generic backends.

mpenet|1 year ago

There 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…).

kaba0|1 year ago

Flamewar-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.

pianoben|1 year ago

I 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.

fulafel|1 year ago

It's an interesting parallel development that people are complaining about the bad original language on both JS and JVM platforms and often using other languages (Kotlin, TypeScript, Clojure/ClojureScript, etc). I guess even Swift instead of Objective-C on the Apple side counts here in a way.

izacus|1 year ago

For posters like you I always wonder: why are you posting? Why did you even click on the article if you dislike Java so much?

Is this posturing? Do you feel cool? Why did you come here and bloviate over something as silly as a language choice?

palata|1 year ago

Can you easily make a Desktop app in Swift (I guess Python, Go and Rust don't fit your criteria) and distribute it to all platforms?

I think anything JVM (be it Java, Kotlin or Scala) would be very good there. A lot better than ElectronJS.

cyberax|1 year ago

> Am I the only one?

Probably not. Java had stagnated for quite a while, entirely missing the lightweight threading and/or async/await revolution of the last decade. The JVM ergonomics also just sucks, a lot of apps _still_ have to use -Xmx switches to allocate the RAM, as if we're still using a freaking Macintosh System 6!

On the other hand, it's a very mature ecosystem with plenty of established battle-tested libraries.