Thanks, I'd rather wait.
Thanks, I'd rather wait.
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 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.
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.
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.
> 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'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.
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).
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.
Thanks, I prefer to wait.
So even if some language feature helps with some problem, the assumption that adding it ASAP is the best way to maximise the integral of productivity over time is not necessarily true. Language features also cost some productivity, and the challenge is finding the right balance. Java chooses to follow a strategy that has so far worked really well.
That’s not to say it failed. Java is one of the most popular languages, but it does suggest real issues with the current approach.
These three languages are often first languages (or, at least, first professional languages), which is a necessary (though insufficient) condition for being super-popular. All of these languages more than make up for the loss of programmers who prefer richer languages with the programmers for whom it's a first (professional) language. Different programmers indeed prefer different languages, but that doesn't mean that the preferences are easily distributed. My rough personal estimate is a 90-10 split, where the 10% prefer more feature-rich, faster-moving languages. That's a very big minority, but Java addresses it by offering the Java language for the 90%, and supporting other languages on the Java platform for the 10%.
You can also see that while the market is becoming more fragmented, no language is currently threatening those top three (although TypeScript could threaten JS, I think), and no language is doing better than them. I.e. other strategies seem to be doing worse.
So knowing that for every X programmers you win you lose Y no matter what you do means that we try to carefully balance the evolution. I can tell you that we are more worried about teachers telling us that Java is getting too many features too quickly, and that it's harder to teach than Python (hence "Paving the Onramp [1] and other planned features) than the programmers asking for more features quicker. The former represent a much larger group than the latter. Also, moving more toward the latter group is both easier and less reversible, so it has to be done with great care.
[1]: https://openjdk.org/projects/amber/design-notes/on-ramp
So Java isn't as dominant as it was 20 years ago, but no one else is, either. And when you compare Java to current landscape, you see that it's in a very enviable position, and it's as safe a bet today as it ever was.
It’s possible though harder to verify if Pascal reached that level and we might see Python hitting it soon.
I don't think Fortran was ever quite that dominant, but we can certainly agree that no language has been as dominant since Java.
> It’s possible though harder to verify if Pascal reached that level and we might see Python hitting it soon.
Not even close for either one of these. I was already programming in Pascal's heyday, and it was mostly used in education. It was never very popular in industry. Python is extremely popular, but many of its users are not professional programmers, and it isn't dominant in big server software at all. In the early 2000s, Java dominated servers, clients, and education. I don't think any language is even remotely approaching that today, but JS would be the closest (although still very far).
Java today is the #1 most popular server-side language, certainly for big software, and by a big margin. According to the best data we have [1][2], it's about 1.5x-2x more popular than C#, maintaining the same gap those two languages have had for about 15 years. It's about 7-15x more popular than Go.
So other JS and Python, all other languages's are doing worse than Java, with prospects that look significantly worse than Java's. No language is even coming close to threatening Java's position as PHP and Ruby were. Node.JS looked like it could have for a while, but then it sank quickly; some thought Go might do it, but while it's certainly interesting and there's much we can learn from it, its growth has stalled.
Comparing Java to itself 20 years ago is unfair, because it was an unusual time for programming. But when you compare it to the competition today, you see that Java is doing spectacularly. I would like to see it taught more in schools, though, where Python has overtaken it.
[1]: https://www.devjobsscanner.com/blog/top-8-most-demanded-lang...
[2]: https://www.hiringlab.org/2019/11/19/todays-top-tech-skills/
Despite what HN suggest sever side programming isn’t that big. Android is currently a major component of it’s position, if you don’t include Android then Java isn’t the most popular language.
Java is practically non existent on client side web, system programming, desktop applications, iOS, scientific computing etc. So only something like 20% of programmers are using Java as their primary language and it might have topped 35% at it’s peak.
Quite the opposite. If you look at the hiring labs data, iOS and Android combined make up less than 1/3 of the Java market alone. That's not surprising. There are lots of mobile apps, but they don't require that many hours of work.
> So only something like 20% of programmers are using Java as their primary language and it might have topped 35% at it’s peak.
But no other single language has better prospects, with only JS and Python in the same game. Java is not as super-dominant as it once was, but it is more dominant than almost any other language in existence. Everyone else is doing worse (or about as well in the case of Python and JS). Moreover, there currently aren't languages that are seriously threatening Java's position as PHP and Ruby (and maybe JS with Node.JS) once were.
The observation that the market is more fragmented than before with all languages commanding smaller portions than some did in the past is true. But if you're worried about Java's position, you need to be much more worried about, say, Go's.
I suspect Python is going to take over from Java fairly soon, even if it might not reach Java’s mid 2000 dominance. That said, Java never reached the dominance of C, and C never reached the dominance of Fortran so I don’t think such arbitrary benchmarks mean much. In absolute numbers we have far more programmers so the next dominant language is likely to surpass past peaks by that metric.
But it's also good to remember that both JS and Python have their own issues, that are by no means smaller than Java's, and neither of them currently threatens Java's dominance on the server, and no one else does either (although PHP and Ruby did in the past).
Some of this is just fads, but I think languages tend to suit the time period when they are most popular. In 1990 C was a hugely dominant force because it suited the kinds of programs being written and the hardware available. IMO Java was a great compromise for late 90’s hardware, but different tradeoffs are becoming more useful resulting in Python’s rise.
Much of this could be fixed with a better tooling and an overhauled standard library, but basic language pitfalls are still a problem.
There were waves. First wave of leaving Java was for RoR. Then there was a period where we had all these JVM languages, with Scala, JRuby, & finally Closure. Then a bit later came Go, which is when I switched.
So why. First wave was due to the god awful experience of building web apps on app-servers. Remember how tedious that was? I forget the names, but there were so many frameworks. And of course imo things like JSPs and Spring also definitely played a part in motivating seeking more pleasant pastures. So this I would chalk to impedance mismatch between Java and the browser tech.
Second wave was more about 'language'. FP. DSLs. Rich Hickey! State is not identity! :)
Third wave was, imo, due to a more seismic shift that included more victims than just Java. This was the beginning of the noSQL era, "simplifying", Redis! What a breath of fresh air. Again, not that Redis made people switch languages, but that there was a shift in mindset as to how to build software. Java all of a sudden looked like the RDBMs second cousin.
Then the cloud. JVM startup times. Memory footprint, etc. I stopped following Java's progress after 2008, but sense this was the period when the Java stewards finally were motivated to be more adventurous with new features. But in the meantime, Go ended up being the server side networking champ.
But now, with things like GraalVM, I'm actually excited to switch back to Java as my main lang again.
Concurrent with all this, fads as you mention; amplification of unseasoned voices via blog-sphere that shifted mindshare; and just the basic human need to seek variety.
Java’s fragmentation also didn’t help as even just web technology evolution though Applets, Servlets, JavaBeans, Spring, JSF etc without letting people settle into something that just worked reasonably cleanly. The perception was always that there was tons of legacy options and sometimes multiple hot new fads creating an endless treadmill where working on the same thing for 4 years left you behind the curve rather than a productive environment.
By comparison .Net benefited from the second mover advantage. Embrace, Extend, Extinguish didn’t work but uniformity brought it’s own advantages and they could always copy and tweak something when it was clearly better.
Finally, there was a perception that the kind of companies using Java where exactly the kind of companies that would soon outsource jobs to India or just underpay and replace everyone with H1B’s.
Async/await provides immediate user value. If people didn't like it they could just use threads in a Java-like style. While some dislike the features, and other push against the sour grapes, its a popular feature found in many languages used by many developers.
Java is popular and so is C# and Javascript, so I can't see how we can draw any conclusions on async/await.
Now, when it comes to async/await, first let's take JS off the table, because JS has no other convenient concurrency feature, and it couldn't add threads because it would have broken most existing JS code (it could add isolates, but they're not sufficiently fine-grained, at least not in the JS world).
If Java had got async/await ten years ago, it would have been burdened with it for decades. It would have provided some value in those ten years, and extracted value for the following forever (albeit gradually diminishing). "Just don't use it" works fine for library features, but not so much for foundational language features, because programmers usually don't start with a blank slate, and don't pick the features in the codebase they work on. Therefore, all language features carry a cost, and they carry a higher cost when it comes to beginners, where this matters most.
It's hard to precisely describe what could have been, but I think most would agree that in those ten years Java didn't lose many developers to languages with async/await because they had async/await. It probably lost some developers to Python and JS for other reasons (say, Python is easier to get started with, and JS is easier for those who know it from the browser), and it didn't even lose that many people to Go (Python lost many more to Go than Java did). Considering all that, I think that Java's position in 2022 is better, now that it has virtual threads, than it would have been had it also had async/await (which would have likely also delayed virtual threads).
If I could go back in time knowing what I know now, I would have advocated against adding async/await ten years ago with even higher certainty. Back then I just believed there's a better way; now not only do I know there's a better way, but I also know that not adding async/await didn't cost us must if at all.
Going back to the original topic, Java's primary competitors -- Python and JS -- also don't have a great solution for nulls. So while I would very much like to address this problem, I see no reason to change our game plan in favour of scrambling for a quick solution. We'll tackle this issue like we try to tackle all others: methodically and diligently, and preferably after we've had time to study how well various solutions work elsewhere.
I think it's pretty depressing to hear that you're numb to this.
TBH, I don't think virtual threads even address this use case in a way that isn't just async/await but less sugared syntax. (Although I'm willing to be pleasantly surprised once new libraries pop up)