Do I use it for personal projects? Nope. Because it's not fun to "drive". For that, I pick the equivalent of a Mazda Miata (insert exciting car of choice), which for me is usually a Lisp.
Do I use it for personal projects? Nope. Because it's not fun to "drive". For that, I pick the equivalent of a Mazda Miata (insert exciting car of choice), which for me is usually a Lisp.
Before, .NET only ran on Windows which disqualified it from many serious applications server deployments. Today, this is no longer the case for everything but cross platform GUI libraries, and even those are an option if you're okay with not having Linux support.
It's more akin to the old car you had just before you bought your Corolla. It was also pretty decent, but it was starting to have issues.
The JVM ecosystem is quite expansive and it's capable of running many things that would be a pain to develop in house (or pay a third party developer for). However, Java isn't the only popular JVM language anymore and you're no longer forced to use Java to interact with its surrounding ecosystem.
The language and the ecosystem around it aren't going to go away for at least a decade, but I think it'll slowly move the way of COBOL and FORTRAN: perfectly good languages, with perfectly good situations they outperform their competitors in, practically exclusively used for niche use cases and legacy software systems.
That could be true of any language that's achieved great popularity, but in 2022 Java is the language that dominates server-side development (by plurality, not majority), it is a technological leader in areas of compilation, garbage collection, and low-overhead in-production profiling, no other single language looks posed to seriously challenges Java's dominant position on the server (as PHP seemed for a while), and, at 27, it is more popular than COBOL was in its (rather short) heyday.
But it is true that Java is among a select set of languages (alongside Python, JavaScript, and C) that have managed to achieve a level of success sufficient to become "a COBOL" or "a Fortran" someday.
Second, while the JDK is pretty modular (e.g. you can use the runtime and tools but not the frontend compiler as "JVM languages" do), we design every feature by looking at the platform as a whole. E.g. the relatively new records feature is implemented in the language, libraries, and VM. That's why some newer Java platform languages have more baggage than the Java language, because their features are not harmonious with the direction of the libraries and VM (e.g. Kotlin's coroutines and data classes).
Finally, it is true that back in the '90s, James Gosling set out Java's strategy to put most innovation in the runtime and keep the language very conservative (he called it "a wolf in sheep's clothing"), and we follow that strategy to this day, because it's turned out to be very successful. While there are lots of programmers who want more adventurous, feature-rich languages -- and many of them hang out here -- the vast majority of programmers don't. Many more people complain that the Java language is changing too quickly than changing too slowly. So it is thanks to the conservative language that the platform is so popular, which allows us to have the resources to innovate in the runtime.
So while <10% of people using Java do so with another language (no single alternative language has gained more than 5% of the platform's ecosystem) -- and we're happy we can accommodate everyone -- the conservative language is a necessary component of making the runtime state-of-the-art. A combination of an innovative runtime and a conservative platform is what most people want, and that combination is the main benefit.
What do you think about JavaScript in this context? JavaScript seems at least as popular among today's full-stack web developers as PHP was 15-20 years ago. V8 might not be as optimal a runtime environment for servers as HotSpot, but that won't necessarily diminish the language's popularity.
The market is much more fragmented than it was in, say, 2004, and so Java is not likely to regain its anomalous overwhelming dominance it had back then anytime soon, but no other language seems posed to do that, either.
EDIT: typos
The Visual Studio team seems to dislike dotnet supporting other platforms, but it's one of the most critical things for its survival. The more the VS team hates it, the more likely it's to be the right choice (probably a good rule of thumb for building IDEs too).
Java generics have a couple of unfixable problems.
For one, you can have List<Foo> and List<Bar> both be passed to a place where Object is expected. But getting them back from that place and trying to recover what was known at creation time, would normally be done with a cast. But List<Foo> and List<Bar> are not runtime distinguishable from each other. Such a polymorphic cast in the code is just syntactic sugar; you'll get a compile-time warning, but no runtime check! E.g. You can get a naked List and cast it to a List<Bar> and then go ahead and try to use it like a List<Bar>. It will only fail when you get an actual non-Bar thing out of the list. It pointedly won't fail if you take your List<Bar> and pass it to other generic code that does more generic stuff with it. And it won't fail if the list is full of nulls, is empty, etc. In essence, it's completely dynamically typed at that point. The static generic types are lies. In reality, all generic Java code compiles down to non-generic code with runtime casts everywhere. That costs performance and means that you can screw up.
Second, erasure also means that you cannot be polymorphic over primitive types in Java, as the VM doesn't support that in the bytecode. So you can't write really basic stuff like Vector<T>, array sorting code, and now, closures and lambdas, that manipulate primitives. All that has to be duplicated, once per primitive type, and for objects. Or you have to box stuff. So they added implicit boxing (autoboxing) so you don't have to type those characters. But they are there in the code. You're stuck with either duplicating for performance (hand-doing template specialization, if you will), or just creating an assload of garbage.
[1] I say "along the lines of". I designed Virgil's generics system not knowing C#, but working from what I knew from ML. It ended up with a lot of the same choices, but I mapped ML's "unit" onto "void" and that works out nicely for zero-arg and/or zero-return functions. You can even have an Array<void> in Virgil! And none of it creates boxes or introduces unsafe casts.
The issue with primitive types and boxing is certainly noted. Hopefully Valhalla will address it and more.
The problem with reified generics is that the same variance model must be adopted by all guest languages on the runtime. Hence you basically don't see any guest languages on the CLR, and efforts by languages such as Scala to port to the CLR failed due to problems interoping with C#. I think one of the JVM engineers "pron" has discussed this multiple times.
I think this is a fair observation, but it really boils down to "a dynamically typed compilation target is an easier target", which isn't all that surprising.
> such as Scala to port to the CLR
I am not as familiar with Scala's saga here, but I've heard multiple conflicting reports from Scala insiders, so I think this is a more complicated issue than just the generics model of the CLR.
Your second point is true though, and the fix is something that requires at least 6 PhD’s combined, but they are working on it.
With significant experience with reified generics, there's just a lot of patterns that you can't do in Java. I wrote a whole PLDI paper about it back in 2013. Reified generics mean you can do stuff like ad-hoc polymorphism without direct language support. Ironically enough, the little trick of hiding type arguments with subtyping but getting them back with casts is a powerful dynamic tool.
What I find strange in these erasure-reification “wars” is that so many other languages get a pass. And I sort of understand that, languages without a runtime seldom have reflection, or only in some primitive form, and most language on top of a runtime are dynamically typed. So outside of guest languages, Java and C# are unique in this aspect, and Java does use reflection very heavily, where I can imagine that restricted access to the whole type may be a hindrance.
Virgil doesn't have reflection, so not a lot of metadata needed at runtime. It does full monomorphization (like MLTon), so you can't have polymorphic recursion. Of course that could go exponential, but in practice I see something like 20%-30% space overhead. I have a tendency to use polymorphism for really generic datastructures, like lists, vectors, maps, but I use tuples a ton and now I added algebraic datatypes. It's a lot of fun and the compiler generates pretty good code and compiles fast--full optimized bootstrap in < 400ms).
Of course everyone worries about exponential code blowup. I have a slightly broken implementation of specialization-up-to-machine-rep, but that's not turned on because of some bugs. I think that's the way I'll go in the future.
It is certainly possible to do a type-passing scheme. The built-in interpreter can interpret polymorphic code using dynamic type environments, but can also run monomorphized code. The interpreter is slow.
One of C#'s biggest assets is Anders Hejlsberg of Turbo Pascal fame. He's been in charge of C# since its inception. He's done a very good job of keeping the language clean and concise, and generally ahead of Java when it comes to adopting features like generics and functional programming.
What’s up with Java in HFT stuff then? I’ve never understood this: from what I understand in order for it to work, you have to intentionally avoid doing many allocations, and that seems like you’ll be throwing massive amounts of the ecosystem (Javas biggest strength) away.
- Mature support for async/await since 2012. Yes, Project Loom is coming, a decade later..
- Support for generic-aware value types (struct vs. class) and low-level features like stackalloc: very valuable for high-performance scenarios and native FFI. See for instance https://github.com/ixy-languages/ixy-languages. In comparison, Java doesn't even have unsigned integers. Yes, Project Valhalla is coming someday.
As well, debatable to some folks, but: properties (get/set); operator overloading; LINQ > Java streams; extension methods; default parameters; collection initializers; tuples; nullable reference types; a dozen smaller features
At least that is my experience running the only .NET team at a company that primarily runs Java.
Might want to give some evidence of this. Also, C# has no plans of green threads. It went the async/await way which is a pain.
As a single anecdote working in both languages in my current job in a cross platform environment when having to write Java it feels just that bit more painful, and just that bit harder to get the same performance for the class of apps I write. YMMV.
I do not know if the problems are related to the Java language or to the typical Java programmers, but Java is the only programming language where I have seen a strong correlation between the programming language used to implement some application and a low quality of that application.
During decades of experience with various programs, whenever I was surprised that a program seemed to be abnormally slow, or it had an unusually ugly GUI, or it had a GUI that was impossible to customize, e.g. it was impossible to change the default font or the size of the font, or it had various other annoying features seldom encountered in other programs, I discovered that it was written in Java.
Most of these annoying programs where commercial programs, some of them very expensive programs.
The most recent Java problem that I have encountered was last year, when I could not install some expensive program, because the installer crashed immediately.
After some time wasted to discover the reason, the conclusion was that the installer was written in Java and it always crashed immediately on any computer to which a 30-bit monitor was connected.
That program had both Windows and Linux versions, but both crashed in the presence of a 30-bit monitor, so the Java installer was of the kind "write once, crash anywhere".
The workaround was to disable the GUI of the installer and make an installation from the command line.
There are some 15 years since I use only 30-bit monitors, but this was the first time when I have seen such a behavior (probably because I avoid Java programs, due to past experiences). Googling has shown that this was actually a well known bug in Java installers, which had not been solved in a long time.
Sure, if we are talking about desktop applications and we ignore the exceptions (Intellij / Minecraft).
The vast majority of Java (=running on the JVM) software these days is server-side, without any user interface.
With Java programs without a Java GUI, I never had problems.
Funny, I hear this sentiment more about PHP which deserved its poor reputation in the early days but is actually quite a nice language now and has been for a good long bit.
I think the biggest problem some people have with certain programming languages is that they don't "look" a certain way they prefer (syntax-wise), or don't have enough modern buzzwords associated with them.
Been a Java dev for ten years and I drive a Toyota Corolla....
...but also in my spare time I play around with Clojure and dream of buying a '69 SS Camaro
Since we're throwing out analogies, Java-the-language is more like a riding lawnmower. It is capable of getting you to your destination, but will be slow and painful the entire time. There is probably some external constraint that you'll be forced to endure this, like losing your license.
Here it is fine I think, the writer of the comment is just explaining their point of view.
What can I say? They get me from claim A to claim B.
So are you saying that analogies should only be used like secondary steering wheels?
A more versatile set of analogirs are of course ATVs, Aircraft, or even the humble legs.
The wider availability also leads to a situation where cars are mostly piloted by random people with no particular qualifications other than a basic license. This can result in lots of car crashes. Of course, it is also possible for a train to get derailed, but this is a rare occurrence. On the other hand a derailing can result in more damage... ah... hmm, I forget where I was going with this...
https://www.fuelexpress.net/blog/just-for-fun/4597-2/
The Corolla is known for reliability and fuel economy. It's the car you'd buy for your fleet so you could ignore it, and then you would ignore it, and some day, people would start assuming you are going out of business or something because all your fleet vehicles are from the late 90s.
On the other hand, the 300 claims to be those things, but has terrible fuel economy, and apparently likes to unexpectedly spin out. They claim that new ESP magically fixes the problem, even though they've been claiming such things for years. It's actually supposed to be a luxury car or something, but apparently for some reason it is used as a fleet vehicle, where it is a poor fit.
Also, since it is a Chrysler, I assume it is unreliable. Oh look, I'm right:
https://cars.usnews.com/cars-trucks/chrysler/300/2011/reliab...
(In fairness, the newer ones are supposedly reliable. Sort of like how Java is supposedly pause free now.)
Filling out the rest of the analogy:
fuel economy => Java startup costs, and asymptotic / constant factor slow downs because it doesn't support zero cost abstraction.
spinning out => The GC, of course
magic ESP => The next GC solves the pause / thrashing issues (promised every year since at least 1998)
reliability => Constant API churn, the 8 => 11 => 17 => 20 treadmill, and (of course) log4j.
targeting luxury segment => Java targeting toasters, IoT and web browsers back in the 90s, but only being able to run on hilariously overbuilt and power hungry enterprise boxes instead. Also, the classloader's open world assumption.
I won’t even correct the others, but how come Java is unreliable? Like, I have a hard time thinking of anything in the category of computer programs that would fair better.
Basic dependencies (like JUnit) break API compatibility every few years, and then they stop distributing the old version for new JVMs, so you're forced to port your code. The GC falls over in production at the least convenient times. People somehow decide everything should be stringly-typed, and that the best choice between .properties, xml and JSON is "all of the above, and also this in-house DSL". There's this common pattern called "vendoring" where you load multiple incompatible versions of the same library into the same JVM, and exploit loopholes in classloader semantics to prevent it from noticing, and ungracefully exiting (which is what it really, really should do).
There's no way to use language improvements and static analysis to improve program semantics over time (like there is in, say C++) because none of the language level abstractions are sound.
For example, you have a line like "static Foo foo = new Foo()". Guess what? foo can be null sometimes. Here's an unrelated problem: Think you have a function that doesn't throw exceptions? Nope. Some third party garbage can throw errors during normal operation instead. Think that eliminating down casts in your program means it won't throw ClassCastException on unexpected lines? That hasn't been true since generics were invented. Think Optional gets rid of null pointer exceptions? Nope. Instead, it's actually a tri-value null. After all, you can always create null references to an Optional (and, looping back to the beginning of the paragraph, you can't avoid creating null references to Optionals in idiomatic code!)
I could go on for hours.
FTFY. And yes, I have worked on old Java apps, they are not worse than any other app that lived for a similarly long timeframe (and the fact that there seem to be more old monstrosity in Java may just mean that it actually manages to do its work written in java, and not fail in some other language).
Why don’t you have a bin repo for old junit versions? Nonetheless, not updating is just technical debt that will have to be paid once either way. Regarding GC, it was never as bad as its name in my opinion, but it improved dramatically in recent years. If it fails it is more than likely a programmer error (which is very easy to debug thanks to the JVM’s killer observability).
Regarding XML and .properties, this is related to enterprisyness not java, nor the JVM. These are meaningful abstractions to a degree but are overdone badly more often than not. Vendoring is not really a hack, it is a correct choice from the JVM’s PoV (in short, a canonical name and a classloader pair is unique inside the JVM), but it can be abused, and application servers kind of do so indeed.
Wtf, Java has probably the best tools when it comes to static analysis. It actually has a well-defined specification of what has to happen under nigh every circumstance, and Java is huge in academy as well so different kind of analysis is an active research topic, especially that Java is also huge in the industry.
Runtime exceptions are a thing everywhere, I again fail to see how are they relevant here, and Java is completely type safe with generics, your statement regarding that is completely false. If you don’t have casts in your program, it can’t fail with classcastexception (reflection-hackery aside).
Optionals are a mistake but the only fault lies in those who put a null inside.
You can't. 'null' represents an empty optional.
If you, or a third-party exposed a "Optional", then it's the API mistake. You're never supposed to expose an Optional as either input or output; they're clunky implementation details of the Java Maybe monad.
There are over three billion active Android devices in the world, since 2014 they have been running Android Runtime runtime environment, which uses Java (or Kotlin) bytecode. Before 2014 Android used Dalvik, which did the same thing. This is running on some pretty low powered devices.
Go uses two build tools for any non-trivial projects. One write in go.mod and another in Make :D (see this - https://github.com/kubernetes/kubernetes/tree/master/build/r...)
https://github.com/gohugoio/hugo
There is a Docker file and some shell scripts, but you build the executable using "go install".
people shit on maven, but i say it's much better than many other built tooling - npm, make, or custom scripts.
The only thing need getting used to is that you cannot and should not stray from the maven model - fit your project's built into the maven model, rather than try to twist maven to do your bidding.
It’s primarily used by enterprise shops. You’d never brag you about driving a van. It’s not fashionable. It’s kinda ugly.
But…it gets the job done.
> To me Java is like a garbage truck. You get to work, start it up, do a nearly invisible but absolutely essential duty, then, at the end of the day, you turn it off and go home. No one dreams about garbage trucks or puts one in a car show but they’re there and ready to go right back to work when you are.
I get frustrated with JSON because of things I could do in XML that I can't do in JSON without breaking the spec. And that doesn't even cover how annoyingly verbose anything done in JSON is.
Anyways.
You're probably right.
> Basically, it's easy to "hold it wrong" in a way that harms consumers.
I feel a bit like this could equally apply to things like GraphQL. I spend more time reading the docs on how someone's internal data model is built than I do writing GraphQL queries. And if I get that data model slightly wrong, my query's garbage.
But that's probably a separate, vendor specific (coughnewrelic), rant.
One that keeps biting us in GQL, for instance, is that it won't let you define a union type for mutation inputs, so you end up needing N methods like `GetByX(X)`, `GetByY(Y)`, `...` instead of a single `Get(X|Y|...)`. Not to mention support for versioning message types, etc...
FWIW: I think proto3 is probably the best I've used, at length and in production. Granted it has its "warts", but the idioms to circumvent them are fairly well-documented and agreed upon, even if they're a bit "ugly" in the syntactical sense.
FWIW pt 2: Like yourself, I think, I would not consider JSON to be appropriate as a schema-defining "contract" language in 2022, for a company that plans to be around in 5 years. There are too many better options available.
Enterprise solutions are often so complex and generic that they can theoretically do and interoperate with anything, but are also hard to get started with and use well.
People like to start with simple things and expand from there instead of buying a whole house when they just want a sink (am I using the phrase right?). In my opinion this makes a lot of because it avoids unnecessary complexity and sensitizes people to why some complexity is in fact necessary.
I know that was my last straw before I started assuming that anything that required XML would be painful to work with. It wasn't an entirely fair assumption, but it was correct often enough that I used it as a helpful heuristic.
No issues anywhere. There's only one point of failure here: bugs in the code generator.
XML means you have to think about how you're architect information exchange much more thoughtfully, because XML is much more strict and follows very explicit rules. It also means you have to develop a schema for your interchange.
With JSON, you can, more or less, just serialize as is, not much thought in the world, and it can be understood by the client. You're not obligated by the protocol to do anything about developing a schema or anything of that nature.
Yes, parts of the XML world have now bled over (defined schema and path algorithms being the big ones I think) but they're optional for better or worse.
Everyone takes the path of least resistance when given the opportunity at the end of the day. This is especially true of software engineers I've found.
In practice, I think most of us used XML the same way that people use JSON today: here's some data from my app, figure out how to pull out the bits you need. No high ceremony required.
But programs that store their data as XML rather than some proprietary binary or text format are awesome.
However, I'm sure a lot of that code still exists.
I enjoy Java. I do not enjoy Spring.
Which was in Java 5.
18 years ago.
A deeply nested JSON document is difficult to navigate in. Even with prettyprint it is counting indentation to find out what kind of info this level has.
Take the html page for news.ycombinator.com and convert the html document into JSON format. It becomes unreadable.
This is precisely one of my complaints against XML, it does depend on whitespace. In JSON, I know that any excess formatting whitespace can safely be removed. But excess formatting whitespace is part of the document in XML and I can't know in general whether it can be safely removed or not.
XML 1.0 was decent but I soured on most of the “standards” based on it after too many iterations of chasing through a chain of specs pulled in by reference where you had to read a bunch of ponderous W3C documents and non-working examples to learn that the spec authors hadn’t correctly modeled the problem, nobody had time to work on any of this, and the only extent implementations either weren’t compatible or had a lot of tedious workaround code. Bonus points if they were replacing a legacy format and ended up with a result which still required deep familiarity with the original format but was also much less efficient.
These problems are cultural. JSON certainly isn’t immune to this but the Java/XML world has more people who felt the need to LARP as Very Serious Architects designing extremely expensive systems. Things like Atom show grownups can use XML, too, but they’re notably the exception.
In Java, the most direct counterparts I see are the places where people felt like they should copy the Sun library developers for code which is far less universally used and took on a huge support cost building abstractions and customization points which were largely unused, often only for security exploits.
But using complex, poorly specified, possibly Turing-complete "config" files written in a markup language that isn't the primary language your app is written in is a serious code smell.
It means you would either be better off using an embedded scripting language (like Groovy) or a better core language.
XML was built for a very limited set of purposes - to create a common base markup for various document formats. It was almost purpose-built to create something like XHTML - a mixed content system where you can do semantic decoration of textual media content, and extend it with things like SVG and MathML.
The problem is that it was _not_ built as a cross-platform data structure interchange format, but it wound up being used for that way more than its intended purpose. This was partially because of the extensibility story - companies could agree on a common base format, and define their own extensions to add additional data. However this was a pain - the XML tooling was often generic to support both kinds of usage, and the language itself was ambiguous because the expectation that the underlying document being described would have document-specific clarifications on use and tooling.
JSON is an object notation - it is a way to transmit hierarchal data. It has limited extensibility in the sense that you can define rules for data processing, such as 'ignore things you don't understand' or 'name things which are not agreed upon with URI rather than short names'.
Trying to use JSON to represent the content model of HTML will just cause pain, because thats not what it was built for. It isn't even re-inventing things from XML, it is just cramming a square peg in a round hole.
Neither format was built to be a configuration file format for users to hand-edit config. As a result, they suffer limitations in their syntax and features (closing elements in XML, quoted property names and lack of comments in JSON being the most commonly cited). TOML is one popular choice for this sort of use case.
It can be argued that, despite not a primary use case for markup, XML has found a useful niche in b2b service payloads and government, banking, and health services in particular. The use case for those might have been "web services" in the original sense where simple CSS-like transforms and styles are applied to payloads for display in browsers, but the JSON community hasn't brought forward a serious replacement for XML Schema, so XML payloads kindof keep sticking around in long-term projects.
A Chrysler PT Cruiser. Odd looking, beloved by its fans, and a reasonably adequate (if quirky) to drive.
This is only an invitation to car-shedding!