Java the language eventually drove me away because the productivity was so poor until it started improving around 2006-2007.
Now I keep an eye on it for other languages that run on the JVM: JRuby, Clojure, Scala, Groovy, Kotlin, etc.
IMO JRuby is the most interesting since you gain access to 2 very mature ecosystems by using it. When Java introduced Project Loom and made it possible to use Ruby's Fibers on the JVM via Virtual Threads it was a win for both.
Charles Nutter really doesn't get anywhere close to enough credit for his work there.
You can take pretty much any code written for Java 1.0 and you can still build and run it on Java 24. There are exceptions (sun.misc.Unsafe usage, for example) but they are few and far between. Moreso than nearly any other language backwards compatibility has been key to java. Heck, there's a pretty good chance you can take a jar compiled for 1.0 and still use it to this day without recompiling it.
Both Ruby and Python, with pedigrees nearly as old as Java's, have made changes to their languages which make things look better, but ultimately break things. Heck, C++ tends to have so many undefined quirks and common compiler extensions that it's not uncommon to see code that only compiles with specific C++ compilers.
It always made me wonder why I hear about companies who are running very old versions of Java though. It always seemed like backwards compatibility would make keeping up to date with the latest an almost automatic thing.
Another problem is crashes. Java runtime is highly reliable, but still bugs happens.
Although Python is pretty close, if you exclude Windows (and don't we all want to do that?).
This takes nothing away from Java and the Java ecosystem though. The JVM allows around the same number of target systems to run not one language but dozens. There’s JRuby, Jython, Clojure, Scala, Kotlin, jgo, multiple COBOL compilers that target JVM, Armed Bear Common Lisp, Eta, Sulong, Oxygene (Object Pascal IIRC), Rakudo (the main compiler for Perl’s sister language Raku) can target JVM, JPHP, Renjin (R), multiple implementations of Scheme, Yeti, Open Source Simula, Redline (Smalltalk), Ballerina, Fantom, Haxe (which targets multiple VM backends), Ceylon, and more.
Perl has a way to inline other languages, but is only really targeted by Perl and by a really ancient version of PHP. The JVM is a bona fide target for so many. Even LLVM intermediate code has a tool to target the JVM, so basically any language with an LLVM frontend. I wouldn’t be surprised if there’s a PCode to JVM tool somewhere.
JavaScript has a few languages targeting it. WebAssembly has a bunch and growing, including C, Rust, and Go. That’s probably the closest thing to the JVM.
No, you really can't. Not anything significant anyway. There are too many deviations between some of those systems to all you to run the same code.
There are differences, but they’re usually esoteric ( https://perldoc.perl.org/perlport#PLATFORMS ).
There's also Groovy.
I wonder what other languages run on the JVM. What about Perl, Icon, SNOBOL, Prolog, Forth, Rexx, Nim, MUMPS, Haskell, OCaml, Ada, Rust, BASIC, Rebol, Haxe, Red, etc.?
Partly facetious question, because I think there are some limitations in some cases that prevent it (not sure, but a language being too closely tied to Unix or hardware could be why), but also serious. Since the JVM platform has all that power and performance, some of these languages could benefit from that, I'm guessing.
#lazyweb
https://github.com/Frege/frege
https://github.com/typelead/eta
Of the others you mentioned, I bet there's a couple JVM Prologs out there, but haven't encountered any myself.
I briefly looked at Frege; both it and the person it is named after are very interesting.
https://news.ycombinator.com/item?id=44112115
https://news.ycombinator.com/item?id=44076220
Full speed ahead, and damn the naysayers, er, downvoters, er, torpedos! ;)
There is an OCaml-Java. NetRexx targets the JVM. For Prolog there are JIProlog and TuProlog at least.
Red basically is REBOL. Yes, Red targets IA-32, ARM, JVM, AVM2, x64, and the CLR.
I’ve seen some experiments for running Perl on the JVM. Rakudo can target the JVM for Raku, which is Perl’s sister language.
For Ada, gnat can target the JVM. https://docs.adacore.com/gnatvm-docs/jgnat_ug.html
For Forth there are a number of implementations. JVMForth, jForth, Misty Beach Forth, HolinJ Forth, bjforth, and xforth at least.
I’ve seen a couple different Java libraries for SNOBOL-style matching but I’ve never seen a SNOBOL tool that targets the JVM.
MUMPS has M4J.
Rust is interesting. There are JVMs written in Rust. There’s support for the JNI for Rust for interoperability. I’m not aware of a JVM target for Rust, though. However, Rust still uses LLVM as its primary code generator. As I mentioned, there are LLVM IC to JVM compilers.
Basic isn’t really a single language. For something like MS Visual Basic, there’s Jabasco. There’s JVMBasic. MBC transpiles Basic to C or C++, so you could use clang to put its output on the JVM. PuffinBASIC is a Basic interpreter written in Java. GLBasic compiles to C++, so again with LLVM all things are possible here. BCX Basic also outputs C or C++. There’s something just called “BASIC Compiler” that is both written in Java and compiles its source to JVM bytecode. The basgo compiler outputs Go code, so anywhere you can target golang code you can target Basic code with basgo, including the JVM. I’m sure there are a lot more. These are different versions of Basic on the source side, some of them similar to one another.
Nimlvm is a Nim compiler to LLVM intermediate code. So once again, as a chain of steps it can be done.
Speaking of chaining translators/transpilers/compilers, did I mention there’s a WebAssembly to JVM compiler? There are actually more than one. Chicory is one and asmble is another. There’s something called “Happy New Moon with Report”. There’s also a WASM written in Scala called Swam. I’m sure I’m missing some.
So the huge and growing list of languages that target WASM can also be chain-translated to target the JVM. That includes C, Rust, Nim, TypeScript, C++, Forth, Go, F#, Lua, Zig, and more. https://wasmlang.org/
So if it targets the JVM, it can run on the JVM. But also if it targets WebAssembly, C, C++, LLVM IC, Lua, Go, and more it can also through other tools target the JVM. Or if it has an interpreter that runs on the JVM because it’s written in Java, Scala, Clojure, or some other language you can get it there. If you really want to get exotic and esoteric, there’s an x86 emulator in WASM out there and you could probably run that on one of the JVM WASM interpreters.
> I can run basically any Perl code back to Perl 4 (March 1991) on Perl 5.40.2 which is current.
Yes, but can you _read_ it?I'm only half joking. Perl has so many ways to do things, many of them obscure but preferable for specific cases. It's often a write-only language if you can't get ahold of the dev who wrote whatever script you're trying to debug.
I wonder if modern LLMs could actually help with that.
From experience, they can.
Java was marketed (at least in its early days) as a WORA language - WRITE ONCE RUN ANYWHERE.
Perl was unmarketed as a WORM language - WRITE ONCE READ MANY (TIMES). ;)
jk, i actually like perl somewhat.
but I think Larry and team went somewhat overboard with that human-style linguistics stuff that they applied to perl.
Can you read arbitrary code written by developers from around the world in PL/1, or Ada, Forth, APL, or even C++? Big languages have lots of syntax choices, yes. It doesn’t need to be abused.
Even C has an obfuscated code contest that’s been going on for decades.
I don’t know if it is a me problem or if I’m missing the right incantations to set up the environment or whatever. Never had that much problems with Java.
But I’m a Java and Ruby person so it might really be missing knowledge.
Your conclusion is correct but not because Python 3 came out in 2008. It was ready to switch to some point a few years later but we'll before 2025 (I don't recall when sorry I didn't do Python at the time!)
Prior to that I would frequently have issues (and still have issues with one-off random scripts that use system python).
I no longer shy away from writing <500 LOC utility/glue scripts in python thanks to uv.
e.g. poetry, venv and pyenv have been mentioned in just the next few comments below yours. and this is just one example. i have seen other such seeming confusion and different statements by different people about what package management approach to use for python.
Which also points to another thing where Java compatibility shines. One can have a GUI application that is from nineties and it still runs. It can be very ugly especially on a high DPI screen, but still one can use it.
(It's still a valid point. It's just not the point you labeled it as.)
int record = 1;
double var = 2;
even though `var` and `record` are now used to create and define things.I am a mere user. I have two Python based systems that worked in Debian 11 and not in Debian 12
Python 3.9 to 3.11 I think was the change.
A
This is not my experience with Java at all. I very often have to modify $JAVA_HOME.
Java is, in my opinion, a complete mess. And I think it's weird how anybody could like it past the 1990s.
C++ not being compilable later hasn't been true since pre standard C++. We're talking 1980s now.
https://blog.habets.se/2022/08/Java-a-fractal-of-bad-experim...
The Java 8 and 8+ divide very much works against this. It was a needed change (much like Python 2 vs 3) but nowhere near pleasant, especially if some of your dependencies used the old Java packages that were removed in, say, OpenJDK 11.
Furthermore, whenever you get the likes of Lombok or something that has any dynamic compilation (I recall Jaspersoft having issues after version upgrade, even 7 to 8 I think), or sometimes issues with DB drivers (Oracle in particular across JDK versions) or with connection pooling solutions (c3p0 in particular), there's less smooth sailing.
Not to say that the state of the ecosystem damns the language itself and overall the language itself is pretty okay when it comes to backwards compatibility, though it's certainly not ideal for most non-trivial software.
I agree it was somewhat painful, but not nearly to the level of the 2->3 change which ended up changing python syntax. Most dependencies worked throughout the change and still work.
> Furthermore, whenever you get the likes of Lombok or something that has any dynamic compilation ... there's less smooth sailing.
Not sure about c3p0, but Lombok goes out of it's way to inject itself into javac internals in order to make it's output changes. It's using the most internal of internal code in order to make that @Getter annotation work. Plenty of other annotation processing APIs are completely unaffected by javac updates because they choose not to use internal APIs. Immutables, Autovalue, dagger2, all examples of dynamic compilation that continue to work regardless the version of java. Lombok is a horrible little dependency that I wish people would abandon. It's making a mess and then complaining that it's somehow Java's fault because Lombok decided it needed access to the AST.
I get it, things have broken. But what has been broken is literally the undefined and non-public APIs which went so far as to call their packages things like `sun.misc.unsafe` just to try and ward off people from using these APIs. (With the javadocs to boot which told people not to use this).
And even with the break, the Java devs went out of their ways to make stand-in apis.
The whole spec was great with the exception of entitybeans.
It provided things that are still not available it anything else.. why do we store configuration/credentials in git (encrypted, but still).
And the context were easy to configure/enter.
Caucho’s resin, highly underrated app server. Maybe not underrated, but at least not very well known
I grew to be a big fan of JBoss and was really disappointed when the Torquebox project stopped keeping up (Rubyized version of JBoss).
After about 10+ years Spring kind of took over JEE.
Omg. Spring was just like moving code to xml. Different now, but still.
What I miss from JEE:
- single file ear/war deployment, today that’s a docker image
- the whole resource api from Java (filesystem/jar doesn’t matter). It means you don’t necessarily have to unpack the jar
- configuration / contexts for settings, + UI for it, database connections etc. Docker kind of works, most most images fail to achieve this. Docker compose kind of takes care of things.
- as said before.. all Java still runs everywhere
In the early 2000's, I used to work on JEE stuff for my day job, then go home and build PHP-based web apps. PHP was at least 10x more productive.
I never understood the fight against ORMs. In the end you'll simply be writing your own framework
Just a lot of boilerplate code, but the overal architecture and structure of JEE is still very sound
What did you like about JEE? I worked in that world for years and don't miss it in the least.
I dunno it just worked for me. But I kept using the standards, no vendor lockin stuff, which bea etc always wanted.
I think the servlet design is great, the whole packaging/deployment model is great. And then well the session beans were overkill in general, so they were swapped out quite early by me. Swapped jsp out for I think velocity templates. And that application is still alive, running, and on the same platform.
And Java meant, at least for me and how I configured it, proper debugging and IDE support (love Eclipse), hot code reload, easy releases, repeatability, ci/cd. The last 20 years, no __significant__ improvements in my opinion.
JRuby could also run on Graal as well.
Fastest at what, exactly?
So giving the entire system to the JVM, performing some warmup prior to a service considering itself “healthy”, and the JVM was reasonably fast. It devoured memory and you couldn’t really do anything else with the host, but you got the Java ecosystem, for better or worse).
There was a lot of good tooling that is missing from other platforms, but also a ton of overhead that I am happy to not have to deal with at the moment.
With the JVM you basically outsource all the work you need to do in C/C++ to optimize memory management and a typical developer is going to have a hell of a time beating it for non-trivial, heterogenous workloads. The main disadvantage (at least as I understand) is the memory overhead that Java objects incur which prevent it from being fully optimized the way you can with C/C++.
Some of those posts "404 The page you have entered does not exist"
So — Fastest at what, exactly? — is unanswered.
(BTW Clojure, as a Lisp dialect, has almost no syntax. You can learn THAT in 5 minutes. The challenge is in training your programming mind to think in totally new concepts)
They're really amenable to the REPL.
Using the function application syntax for primitives like + is nice because you get the same flexibility of normal functions, like variable argument length: (+ a b c).
Clojure is a little bit less uniform than other Lispy languages in that it has special brackets for lists (square brackets) and for maps (curly brackets), but that's pretty much it.
i am not a clojure or lisp expert, just saying.
and that's before you throw in real multithreading
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
> iirc
49.88—55.68 secs wall clock
7.66
5.51
27.85—27.91
83.79—87.16
10.94—11.09
How long a runtime would be required exactly, on what class-of hardware, to pass the True Scotsman?Please provide alternative benchmarks that you accept.
I'd also throw in what was possibly their greatest idea that sped adoption and that's javadoc. I'm not sure it was a 100% original idea, but having inline docs baked into the compiler and generating HTML documentation automatically was a real godsend for building libraries and making them usable very quickly. Strong typing also lined up nicely with making the documents hyper-linkable.
Java was really made to solve problems for large engineering teams moreso than a single developer at a keyboard.
Indeed. Many languages have something similar to Javadoc, yet somehow I haven't encountered anything quite as good as Javadoc, and I can't explain why or exactly how it's better. I admit I haven't tried that hard either. But I suspect it's down to the nature of the language and how, with well designed libraries at least (and not all are, certainly,) there is a nice decomposition of modules, packages, classes/interfaces and methods that leads to everything somehow having a correct place, and the Javadoc just follows. The strong typing is another contributor, where 90% of the time you can just look and the signature and imply what is intended. Finally, the old-fashioned frames based HTML typically used with Javadoc is a great benefit.
Also, I've found I experience less reluctance to author Javadoc for some reason. Again, part of this is due to strong types, and much of the legwork being correctly generated in nearly every case.
Lombok, when used with moderation, is wonderful. Mockito is magic, of a good kind. Maven still gets it done for me; I've yet to care about any problems Gradle purports to solve, and I think that's down to not creating the problems that Gradle is designed to paper over in the first place.
Today, if I had my choice of one thing I'd like to see in Java that doesn't presently exist it's Python's "yield". Yes, there are several ways to achieve this in Java. I want the totally frictionless generators of Python in Java.
The GC story is just great, however. Pretty much the best you can get in the entire ecosystem of managed-memory languages.
You have different GC algorithms implemented, and you can pick and tune the one that best fits your use-case.
The elephant in the room is of course ZGC, which has been delivering great improvements in lowering the Stop-the-world GC pauses. I've seen it consistently deliver sub-millisecond pauses whereas other algorithms would usually do 40-60 msec.
Needless to say, you can also write GC-free code, if you need that. It's not really advertised, but it's feasible.
As someone who's always been interested in gamedev, I genuinely wonder whether that would be good enough to implement cutting-edge combo modern acceleration structures/streaming systems (e.g. UE5's Nanite level-of-detail system.)
I have the ability to understand these modern systems abstractly, and I have the ability to write some high-intensity nearly stutter-free gamedev code that balances memory collection and allocation for predicable latency, but not both, at least without mistakes.
The GC would be the least of your problems.
Java is neat, but the memory model (on which the GC relies) and lack of operator overloading does mean that for games going for that level of performance would be incredibly tedious. You also have the warm up time, and the various hacks to get around that which exist.
Back when J2ME was a thing there was a mini industry of people cranking out games with no object allocation, everything in primitive arrays and so on. I knew of several studios with C and even C++ to Java translators because it was easier to write such code in a subset of those and automatically translate and optimize than it was to write the Java of the same thing by hand.
It is not feasible under the JVM type system. Even once Valhalla gets released it will carry restrictions that will keep that highly impractical.
It's much less needed with ZGC but even the poster child C# from the GC-based language family when it comes to writing allocation-free and zero-cost abstraction code presents challenges the second you need to use code written by someone who does not care as much about performance.
The downside is that you sacrifice a lot of the benefits of guard rails of the language and tooling for what may not end up being much savings, depending on your workload.
I think that's mostly done in organisation where there's time, budget and willingness to optimize as far as possible.
Sacrificing the guardrails doesn't make sense for the "general public" software but does tremendous sense in environment where latency is critical and the scale is massive. But then again, in those environments there are people handsomely paid to have a thorough understanding of the software and keep it working (making updates, implementing features etc).
I worked on a software that was written to be garbage-free whenever it could. Latency (server-side latency, i mean) in production (so real-world use case, not synthetic benchmark) was about 7-8 microseconds per request (p99.9) and STW garbage collection was at around 5msec (G1GC, p50, mostly young generation) or ~40 msec (p99.9, full gc) and was later lowered to ~800-900 microseconds with ZGC.
I know it might sound elitist but the real difference here are... Skill issues. Some people will just shun java down and yap about rewriting in rust or something like that, while some other people will benefit from the already existing Java ecosystem (and tooling) and optimize what they need to get the speed they're targeting.
I know I'll be downvoted by the rust evangelism task force, but meh.
yes.
> I suspect most people shun it because database access- especially if the DB itself is over the network on a different machine- already slow enough that ZGC / zero allocation won't be noticed.
Database access, if you're talking network latency query/transaction processing time, is essentially irrespective of the language being used, so that's not a good reason to shun Java as a language/rutime anyway.
If you have the extra network latency from external services, you need some pretty outrageous traffic for GC to become a problem, I would think.
There's no value types (outside primitives) and everything is about pointer chasing. And surely if there was less pointer chasing it'd be easier to do the GC work at the same time.
When Java got popular, around 1999-2001, it was not a close third behind C (or C++).
At that time, on those machines, the gap between programs written in C and programs written in Java was about the same as the gap right now between programs written in Java and programs written in pure Python.
A mix of K&R C, C89, C++ARM compilers catching up with WG21 work, POSIX flavours, and lovely autoconf scripts.
That was my point - performance was never one of the primary considerations for enterprises. They had more important considerations.
That is one of the things I have been doing across JVM/ART, CLR, V8 for decades now, moreso if we include Perl and Tcl into the mix, I seldom write full blown 100% C or C++ code, when I reach to them, is to write native libraries or implement language bindings.
This is something I greatly value with the recent changes to Java. They found a great way to include sealed classes, switch expression, project Loom, records that feels at home in the existing Java syntax.
The tooling with heap dump analyzers, thread dump analyzers, GC analyzers is also top notch.
Hearing the work he and others did to gradually introduce pattern matching without painting themselves into a corner was fascinating and inspiring.
Not anymore, the competition is doing much better these days.
Java's tools are really top notch. Using IntelliJ for Java feels a whole new different world from using IDEs for other languages.
Speaking of Go, does anyone know why Go community is not hot on developing containers for concurrent data structures? I see Mutex this and lock that scattering in Go code, while in Java community the #1 advice on writing concurrency code is to use Java's amazing containers. Sometimes, I do miss the java.util.concurrent and JCTools.
The patterns are available, its up to the community to apply proper concurrency patterns.
You can use platform threads, user-space threads, language-provided "green" threads, goroutines, continuations or whatever you wish for concurrency management, but that's almost orthogonal to data safety.
It’s not that you need locking to use threads. You need locking to stop threads from ruining any shared resource/data they are both trying to touch at the same time.
https://github.com/crossbeam-rs/crossbeam/blob/master/crossb...
I can't find any references to a "crossbeam dequeue" outside of Rust sources. Is this a neologism for a "very common" pattern, or just very common in Rust?
The generic name is just Deque. https://en.wikipedia.org/wiki/Double-ended_queue
Don't communicate by sharing memory; share memory by communicating.
The overuse of Mutex and Lock are from developers bringing along patterns from other language where they are used to communicating via shared memory. So this aspect of the language just doesn't click as well for many people at first. How long it takes you to get it depends on your experience.But then I have also encountered Rust people that will look down on Java but had no idea buffered I/O had higher throughput than unbuffered.
Unbuffered IO is a tradeoff. For certain use cases it does help, because throughput isn't everything. I'm sure Buffered is better in the average use case, but that doesn't mean you would never need unbuffered.
Like streaming arrays one byte at a time through the channel.
Such devs just aren't very good, and hear "Google internally recommends not using them in many situations" but jump to inferring that means all of their situations qualify.
> but that doesn't mean you would never need unbuffered.
Note that this was never claimed.
In fact my experience has been that overuse of channels is a code smell that alot of new go developers fall into and later regret. There's a reason the log package uses a mutex for synchronization.
In general I think channels are great for connecting a few large chunks of your program together. Concurrency is great but also not every function call benefits from being turned into a distributed system.
I think that it would be a great idea to develop more concurrent go data structures with generics and I suspect inertia is what's keeping the community from doing it.
My credentials such as the are: been writing go since 1.0. worked at Google and taught go classes as well as owned some of the original go services (the downloads server aka payload server).
Edit: 1.4, not 1.7
The fact that you specifically mention Go explains a lot. btw c# is faster than Java, so not third place, it's more a 5th~
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Benchmarks aren’t all that useful since usually the bottleneck is File IO, external api calls, db calls, user latency or a combo of the 4.
Go’s main advantage in this matchup would be conciseness.
Go code looks so clean and nice, Java doesn’t.
I personally don’t care for Java, but I have bills so it’s always in my back pocket. Things happen , sometimes you need to write Java to eat.
“Fred, you really should just take the job.”
“Martha you don’t understand, it’s Java with an Oracle DB.”
“Fred, I know it’s bad, I know you still have nightmares about the 4 types of string in Java 8, but it’s not just us now.”
With a tear in his eye , fear in his heart.
“Martha, if I must… I’ll open Eclipse once more.”
I write Java to pay bills and my eyes and fingers thank me everyday for sparing them from a sea of if err != nil. I won't even go(!) into the iota stupidly compared to Java's enums.
I built a small phone app with it. The best way to describe it is incomplete. I think the philosophy is to make things more minimal?
A lot of frameworks don’t exactly do everything they need to.
I’ll still pick it over Rust, which seems to like punishing the developer.
Only have to deal with gigalines of log4j excreta filling up disks.
But if your organization doesn't assign that work to you, then sure, it's not your problem.
Java, .NET and languages like that also lend themselves pretty well to tools (and even LLMs) understanding what's going on, their runtimes are pretty good and platform differences don't give you too many issues from what I've seen. Though when it comes to the frameworks or libraries you might use (e.g. how often you will see the likes of Spring Boot in enterprise projects) will definitely leave some performance on the table [1] and have plenty of awkward and confusing situations along the way [2], especially if you're unlucky enough to have to work on codebases that have been around for over a decade. Old Java projects really suck sometimes, though maybe that applies to many of the old projects, regardless of tech.
Overall, I quite like them and am pretty productive, plus I unironically think that using Maven is pleasant enough (even adding custom repos isn't too convoluted [3]) and the modern approach of self contained .jar files that can just be run with a JDK install instead of separately having to manage Tomcat or GlassFish (or TomEE or Payara nowadays, I guess) is a step in the right direction!
Though while I do like packages such as Apache Commons and they're very useful, I also very much enjoy using something like Go more recently, it's easier to get started making simple web apps with it, less ceremony and overhead, more just getting to writing code.
[1] https://www.techempower.com/benchmarks/#section=data-r23&l=z...
[2] https://blog.kronis.dev/blog/it-works-on-my-docker (a short rant of mine, but honestly I very much prefer when you have configuration done explicitly in the code, not some layered abstractions with cryptic failure modes; Dropwizard is way nicer in that regard than Spring Boot)
[3] https://maven.apache.org/guides/mini/guide-multiple-reposito... and https://maven.apache.org/guides/mini/guide-mirror-settings.h...
Of course, rank depends on what we include or exclude from the rankings, for example:
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
:versus:
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Java syntax isn't perfect, but it is consistent, and predictable. And hey, if you're using an Idea or Eclipse (and not notepad, atom, etc), it's just pressing control-space all day and you're fine.
Java memory management seems weird from a Unix Philosophy POV, till you understand whats happening. Again, not perfect, but a good tradeoff.
What do you get for all of these tradeoffs? Speed, memory safety. But with that you still still have dynamic invocation capabilities (making things like interception possible) and hotswap/live redefinition (things that C/CPP cannot do).
Perfect? No, but very practical for the real world use case.