Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Can you point a couple of cases where Java got a better version?

Generics? Value Types? Lambdas? Null Safety? Async/Await?

Also do you just have to assign all the value the features provide in interim 0 value? Like Async/Await has provided a 10 years of value, and I'm guessing you mean Project Loom... so how much better than Async/Await does Loom have to be to justify an entire decade of just straight up missing the value add entirely, let alone having a better one

-

I can't reply to comments anymore (thanks dang) but yeah...

Generics at the Java layer are worse, generics at the JVM layer are convenient if you're going to write a language targeting the JVM. That's just an artifact of the fact that the JSR for Generics defined backwards compatibility as its top goals, not because they were trying to enable a friendlier runtime for languages that didn't exist yet.

I already addressed Project Loom: They're coming a decade after async/await are coming after a decade of a strictly worse concurrency story, so unless you're assigning 0 value to a decade of having a better situation (which I'd say is disingenous) I don't think it's a great example.

Also definitely not sure how Java Records are better than C#?



I can! Generics, virtual threads, and records. Java is unburdened with the prevalent and obsolete features of async/await, properties, and its generics allow a flourishing ecosystem in exchange for a minor inconvenience.


> Java is unburdened with the prevalent and obsolete features of async/await, properties, and its generics allow a flourishing ecosystem in exchange for a minor inconvenience.

I don't quite get the "unburdened" part. C# now has records as well[1], and it always had List<Object>. It may also get stackful coroutines as an alternative to stackless coroutine.

You could say that C# now has to deal with a lot of legacy code that's using properties and async/await and cannot be replaced with "superior" records and stackful coroutines[2]. That's all true, but Java hasn't been frozen in vacuum for the last 20 and 10 years (respectively).

While C# programmers created mountains of legacy code with properties, Java developers churned out mountains of legacy code using "Beans" with getters and setters, auto-generated by the IDE or Lombok. That's strictly worse.

At the same time during the last 10 years, Java programmers that needed Async I/O didn't just sit around and wait for Project Loom. They wrote callback hells, and then moved on to CompletableFuture or a reactive programming style. And all this code tends to be a lot messier than Async/Await.

In short, real world Java developers are just as burdened as C# developers by legacy solutions that predate virtual threads and records, and the Java legacy solutions are usually quite a lot uglier.

[1] Although I dislike their decision of permitting mutability, their records they are at least useful right now, since we don't have to wait another 5 years to get a with expressions.

[2] I completely agree with you that immutable equality-based types are superior, and that mutable data types probably shouldn't be baked in the language. But I disagree with the stance that stackful coroutines are superior.


> I don't quite get the "unburdened" part.

Then let me explain. Some programmers (~10% by my educated guess) like languages with lots of features, but most don't; really don't. It seems that being able to serve as a first language is a prerequisite for being super-popular (and Java, Python and JS serve in that role), and having more features is a big hindrance to that. We are more concerned with Java having too many features than too few (and teachers complain about that).

Every additional significant language feature has a cost, and often for every experienced developer it gains, it loses several beginners. The trick is balancing the benefit and the cost, and in Java we do this by adding features slowly, and trying to pick only the ones that give a lot of bang for the buck (which means we often add features relatively late, after they've proven themselves elsewhere). This strategy -- originally laid out by James Gosling in the mid-90s -- works, and no other strategy has so far proven to work better.

> That's strictly worse.

It really isn't for languages seeking to be at the top for the reason I just explained. But even if you think there's some subjectivity there, the objective fact is that no language with a strategy of adding features quickly has performed better in the market than Java. The only languages in the same tier have even fewer features. So there is no objectively measurable metric by which it is worse: languages that add more features more quickly don't fare better (in fact, they seem to fare worse), and no significant differences in productivity or correctness have been found (despite trying).

> and the Java legacy solutions are usually quite a lot uglier

I think they're usually quite a lot nicer, but people have different preferences.

> But I disagree with the stance that stackful coroutines are superior.

Okay. There aren't many things all developers agree on.


> Then let me explain. While some programmers (~10% by my educated guess) like languages with lots of features, but most don't; really don't. It seems that being able to serve as a first language is a prerequisite for being super-popular (and Java, Python and JS serve in that role), and having more features is a big hindrance to that. We are more concerned with Java having too many features than too few (and teachers complain about that).

Programmers want to deliver working code. If that code needs to be asynchronous and handle data, they'll use whatever is easy, acceptable and available to use with their language. That "feature" may be provided by the language, by a compiler, by IDE code generation, by a pre-processor, by a post-processor, by runtime code generation or by a library that is using some idioms.

Most programmers (my educated guess is 80%) don't care very much how they get that done, as long as they can get quickly learn it and get stuff done keep their managers and co-workers are happy. Programmers need to go through a learning curve to learn new features, whether they are library features or language features. A language can "cheat" a little by keeping itself lean and mean and deliver data class creation to IDEs and annotation processors, while letting libraries implement concurrency and even coroutines (see Quasar for Java and Greenlet for Python).

This doesn't remove any complexity from the programmer dealing with these languages. Some times it could make the programmers' life even more miserable since there are multiple competing methods to choose from.

Having led programmer teams working in both C# and Java, I can clearly say that C# programmers are less confused by data classes and concurrency issues. I wouldn't say C# is perfect (C# properties are messy and their async/await implementation is pioneering, but somewhat confusing). I don't like all features that get added to C# either, and I sometimes think Microsoft could exhibit more care here. But I feel less "burdened" when we have to use C# (or Kotlin, Go or to certain degree Rust) for concurrency and asynchronous I/O rather than using Java and JavaScript, which have way too many historical ways of doing the same thing.

I think you're thinking too much from the perspective of a _language developer_. Language developers like less complexity in their languages, and that's totally understandable. But developers don't care so much about that, and despite what you say, I don't think there's good evidence that this is what makes a language extremely successful. The process of a language becoming successful is a lot more complicated than that and I doubt if it can be easily described. After all, the historical data we've got is too sparse. But if we look at languages that did become successful before and after Java, most of them were quite complex compared to their competitors:

PL/I was considered extremely complex and bloated in its time, but it became popular nevertheless, since it had a strong corporate backing from IBM. The very same company, incidentally, was one of the largest corporate backers of Java since the early 1990s.

While C was arguably almost as lean as Pascal (if not as easy to learn), it barely got any foothold in the world where Java has won so decisively later: Enterprise line-of-business software. These programs tended to be written mostly in COBOL and PL/I on mainframes, and on the PC developers used whatever was available, including assembly. Smalltalk (not a "simple" language for its time, considering the _entire_ package you'd get) also had a short heyday. But when Java came out, the world settled on C++. Sure, C++ back then was less than the shining paragon of feature creep that it is today, but it was still a rather complex language. The various dialsects of object-oriented Pascal were simpler. Modula 3 was simpler. Smalltalk was probably simpler too. But C++ won.

In the defense industry during the 1980s, Ada was queen. The reasons for this are really simple: this was often what the DoD mandated. Just like many corporate IT departments mandated Java years later. Anecdotally, all Ada programmers I met loved the language back then. They didn't lament the massive amount of features (for the time).

Embedded languages are also an interesting case. Small languages like Lua are quick objectively easier to embed and you'd think they'll win decisively. Lua is quite popular as an embedded language, but it seems to be on par with Python and losing to JavaScript.

Why did JavaScript become so popular? It's certainly not a simple language. There are many complex features that are not used very often like proxies, generators and all the various Object functions. There are often several layers of historical cruft or different solution strategies, such as prototypes vs. Object.create() vs. classes. Or "Error(...)" vs. "new Error(...)" or var vs. let. Or this-binding arrow functions vs. traditional anonymous functions and Function.prototype.bind(). Equality laws type coercion are famous bonkers[1]. Even from its very inception, JavaScript was more complex than necessary, and made some decisions that kept annoying generations of developers (e.g. vars and prototypes). And it still won, since Brendan Eich got included in Netscape and Microsoft rushed to copy it with (the frustratingly randomly incompatible) JScript. JavaScript never made developers happy and still has a certain type of fatigue named after it.

> the objective fact is that no language with a strategy of adding features quickly has performed better in the market than Java

This is deductive reasoning from a single datum, where there are many other social and technological factor that could determine language success. The fact is that before Java, the most successful languages - especially in the same industry Java rules most strongly today (business programs) - have been rather complex: COBOL, PL/I, C++. And to the best of my knowledge, they all had strategy of indiscriminately adding features in the language level.

I fail to see any strong evidence to your claim, while there is some anecdotal evidence to the contrary.

>> But I disagree with the stance that stackful coroutines are superior. > Okay. There aren't many things all developers agree on.

That's great, but then it's just opinion. I personally prefer stackless coroutines, but I won't go ahead say they're strictly superior to stackless coroutines. There's a reason many languages still chose to go with stackless coroutines even though stackful coroutines are far from new. Swift has added async await quite recently an I'm pretty sure Apple was fully aware of the work done on Project Loom, Go, Lua, Erlang and many others. Microsoft could have very well chosen stackful coroutines for C# and implemented them to be transparent like virtual threads. gevent was doing the same thing (in a more primitive way) in Python after all. It's not like stackful coroutines are a new kind of tecnology we had to sit and wait for years to research properly.

[1] https://www.destroyallsoftware.com/talks/wat


I understand your perspective though I disagree with some of the observations, but I still don't see why any of this should convince us to switch strategies for Java given the following two facts: no other strategy has proven to work better, and claims about added productivity/correctness could not be established. So this all comes down to you liking different things, but that some developers want the opposite of others is a given. No matter what we do, there will be people trying to get us to do the opposite. So even coming to this with a blank slate and knowing nothing about programming, it would be irrational for us to change our strategy.

> This is deductive reasoning from a single datum

I don't think that's true, but even if it were, we don't need evidence to support us not changing our strategy; we need evidence to convince us that we should.

> especially in the same industry Java rules most strongly today (business programs) - have been rather complex: COBOL, PL/I, C++

I disagree. C was still more popular than C++ in the nineties, and compared to the average of the time, COBOL was simpler than C#. But even that doesn't matter. Teachers are telling us that if we increase the pace, even more of them would switch to teaching Python.

> It's not like stackful coroutines are a new kind of tecnology we had to sit and wait for years to research properly.

It's not as simple as that. Implementing user-mode threads is drastically more difficult than async/await (and requires deep compiler backend and runtime changes). Doing them competitively efficiently also requires a good GC. The .NET team said that they weren't sure that adding user-mode threads in a compatible way is possible in a large existing ecosystem, and they have some bigger challenges than Java (such as pointers into the stack). Languages that target LLVM have additional challenges. The idea is very well known, but good implementations are much harder than async/await, especially in established languages.


> I understand your perspective though I disagree with some of the observations, but I still don't see why any of this should convince us to switch strategies for Java [...]

I'm not really arguing for that. I'm really not advocating any school of language design here. I'm just saying that from the point of view of _the users_ the actual purity of the core language matters less than the state of the ecosystem.

I'm perfectly happy with the current course of Java, especially post Java 8. It just isn't for me, and I wouldn't use it or recommend using it for most types of software I'm dealing with. I can say the exactly same for C++.

There's a place for conservative and highly selective languages like Java, C and Go. As a CTO or a tech lead I generally tend to avoid these languages and I don't think they work great for my organization, but they might work out for other people. It's good to have choice. And it goes both way: if you need to stay within the JVM and you're not satisfied with Java, you've got Scala, Kotlin and Clojure. Between them, thy cover a lot of ground and have very different strategies for adding features.

The most conservative users of Java have their choice though. They don't care very much about the absolute _size_ of the language, but they very much dislike change. And for these businesses, the current pace Java is moving at is still too fast. That's why we still have a great deal of businesses out there running Java 8 with outdated frameworks and libraries. But they're not unhappy with Java, since they could always stay at an older version - and that's exactly what they do.

> I disagree. C was still more popular than C++ in the nineties

I was talking specifically about the industry which is now dominated by Java: business software. C++ strongly dominated two industries throughout the 90s: post-mainframe business software of all kinds and desktop GUI software. C never came close to dominating business software. On the early days of the desktop these were often written in Basic or Pascal and by the 1990s C++ became the standard object oriented language, although most of its competitors were simpler. C was probably dominant in early desktop GUI software, but was completely replaced[1] by C++ and other languages by the mid-1990s. C was still dominant in games throughout the 1990s, although C++ would come to dominate this industry later on.

> and compared to the average of the time, COBOL was simpler than C#.

I disagree that COBOL was simpler than earlier languages like FORTRAN or LISP, or contemporaries like ALGOL 60, but it's probably a moot point. COBOL was not a general-purpose language at that point, and it's structure was quite unique.

> But even that doesn't matter. Teachers are telling us that if we increase the pace, even more of them would switch to teaching Python.

I'm a bit surprised by this sentiment, since Python has been steadily adding major features since its very inception, while Java only increased its pace rather recntly, starting with Java 9. Python started gaining popularity as a teaching language during the priod it was moving faster than Java.

> It's not as simple as that. Implementing user-mode threads is drastically more difficult than async/await.

I completely agree with you here. This must have been a major part of the .NET team's rationale. But they could have undertaken a multi-year project to implement it like you did. The end-result probably would have been the same: a variety of community-based projects that try to bring async I/O and M:N concurrency to the language.

[1] Outside of small holdouts like Gtk and Carbon I guess.


When we ask companies why they picked Java, they mention backward compatibility, a good combination of performance, productivity and observability, and sustained popularity that means a large ecosystem and hiring pool and a good predictor of future popularity, which, alongside with backward compatibility means there's a good chance that their investment will be preserved.

Unlike runtime features, such as great GC performance and observability tools, specific language features or lack thereof don't usually come up, so I don't know if that has a direct or an indirect effect, and it's certainly possible that had the Java language been less conservative it would have achieved similar success. It's just that no one has ever managed to do that, so there's no reason to change course. (We can argue over C++, but its super-popularity was very short-lived, certainly compared to Java)

A direct effect that we do know about is teaching. Teachers do tell us that they don't like teaching rich languages as a first language. I don't think that the absolute pace matters so much, but rather the complexity of the language compared to alternatives. Teachers pick from a (very small) selection of relevant languages, and language simplicity is one of the important factors (so they tell us). In particular, those who pick Python always mention two factors: its simplicity compared to Java and the ease of getting started, which is why we'll be trying to address that second factor.

> And for these businesses, the current pace Java is moving at is still too fast.

The concrete issue is actually the difficult migration from 8 to 9+, which happened because Java lacked strong encapsulation until JDK 16, libraries depended on JDK internals, and those internals changed with changes to the runtime and libraries. Libraries quickly updated, but some did so with breaking changes of their own, which meant that old products needed a bit of work to upgrade, and some of them didn't have sufficient personnel. They are a minority now, though. This would have happened even with no changes to the language (and there weren't many in 9).

> while Java only increased its pace rather recently, starting with Java 9

More precisely, it returned to its former pace after years of relative stagnation due to diminished resources. Although it may appear faster because partial language features are trickling in every six months rather than in a more complete form every three years. We're trying not to exceed that original pace, and yes, we are selective and conservative, in line with Gosling's original strategy of "a wolf in sheep's clothing" (an innovative runtime wrapped in a conservative language).


.NET's async is far from great, but Loom/vthreads is an impressive achievement in distilling all of the mistakes that .NET made, while learning from none of the good ideas that it (or future promise/async/await) had.


I guess he's talking about project loom (fibers, go style concurrency) which IMHO is a much better solution than async/await, but yeah... took some 10 years to arrive.


During the last 10 years, the Java ecosystem has heavily invested in reactive APIs, so it's not like if Java devs have no option.

And IMO, the semantics of any reactive APIs is better than just providing await.

Await serializes the async calls instead of running them concurrently. And too few C# devs are aware of/using the Task API.


And saved millions of developer minds not having to deal with mind bending async/await.

Thanks, I prefer to wait.


Do-notation is much simpler than callback hell


You could have had the Loom experience 20 years ago by just spawning OS threads. Of course, there's a reason that this was discouraged... threads quickly turn into a nightmare to manage safely, especially when they need to interact.


Genuine question, how is managing cross interacting virtual threads any different or easier than managing interacting threads? I say this and I am greatly looking forward to using Loom in production. It's definitely the correct way to go as opposed to async/await.


It's not. That's the problem with the thread API that Loom is so dead set on preserving, and the big improvement that promises/async/await provide over threads.


How does async/await improve on managing mutable state across threads of execution (tasks/promises/etc?)


Structured concurrency.


Issue with os threads is that their number is limited. Not the issue with communication. Futures are good enough for that, if you need more then structured concurrency.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: