393 comments

[ 1.2 ms ] story [ 299 ms ] thread
I don't have a ton to say here, the article says it all really. But this also reflects my experience when developing with Scala and although I love the language and its brevity, I went back to Java because I hated the Scala toolchain, sbt, dependency issues, etc. Basically, I like the language in isolation but the overall experience was horrible.
Java has the same dependency issues? I vividly remember spending days on jars shading in Maven. Basically, a single approach that would solve this, irrespective of the language, would be isolating dependency trees of every library from each other, essentially duplicating the code of many common libraries in RAM (like Docker, but for libraries inside the same process). There's an option to do that in Maven, but it's not the default. And it still would not work for dependencies where there should be only a single instance of it in RAM, like for example loggers...
> Basically, a single approach that would solve this, irrespective of the language, would be isolating dependency trees of every library from each other

Doesn't solve the problem completely because it is normal that applications need libraries to interoperate; consider case where application is passing objects between two libraries that both use types from a third library.

Then your app would explicitly be doing the impendance mismatch resolution (converting objects from one version of library to the other) when doing the library calls.
which someone would have to code in as that's not automatically possible all the time.
You're pretty much screwed in that case but that's kind of by design and the entire point of versioning, isn't it?
A major problem is that Maven (and friends) doesn’t distinguish between API dependencies (the API of a library using types from the API of another library) and implementation dependencies (a library depending on another library as an implementation detail). If that distinction were made consistently, implementation dependencies could indeed be separated into a dedicated classloader for each library, and you’d only have to worry about API dependencies, which would go a long way.

The Java 9 Modules architecture would have been an opportunity to introduce something like that, but alas they didn’t.

OSGi allowed you to specify in excruciating detail what dependencies you had, whether API (i.e you wanted to re-export types from another library) or not, and much more. Unfortunately, it became far, far more complex than just implementing a simple module system, so as most things from the era (early 2000's) it became a huge, complex beast no one wanted to touch anymore.
I believe that separating interface from implementation doesn't really solve the problem, it just shrinks it. E.g. what if you depend on two libraries that re-export classes from different versions of a third library?

I think that if you truly want to solve the problem, you need to extend the definition of the fully qualified classname to include the notion of a breaking version reference. Kind of like what folks now sometimes do the hard way by encoding it into the package name.

This would make it possible to directly address the two different versions from the same calling source file.

I agree, but I believe the “shrinkage” would already reduce the problem substantially, and maybe more importantly, would make developers more careful about what they include as interface dependencies instead of as just implementation dependencies.
Jep, this is really an issue of how the JVM and Classloaders are architected. Rust essentially chooses the other side of the sea, which is better in some sense, but worse in others (which we will see once the ecosystem grows).

A configurable middleground is needed, but it's not an easy task to get that done.

Essentially OSGI is that. It is still a ballache tho, and slow to boot, so I would not recommend it.

Best bet it to be picky about dependencies that respect backward compatiblity or do name changes (like commons collections4)

(comment deleted)
I have personally spent so much time fussing with runtime ClassDefNotFound and MethodNotFound errors in Java that I am no longer able to respond to assertions that Java is type-safe with anything but an incoherent stream of cursing and rage tears.

But Scala somehow seems to take all of that and intensify it. I have heard that Scala 3 is supposed to improve this, but I don't anticipate being able to adopt Scala 3 before the heat death of the universe.

Not sure what you're doing with Java but that's not a common problem at all. Are you just aggressively stripping code and dealing with the fallout?
Working on projects that involve big frameworks with deep and ever-shifting dependency trees. So upgrading an existing dependency or taking a new one could often be a risky move.

Ground zero for most of them was Guava, which I unfortunately could not avoid due to it being a transitive dependency. And, even more unfortunately, Guava types were being exposed on the direct dependency's public API, so package relocation was not an easy option.

Guava is an outlier. While they do honor semver, they’re already on version 31.1, meaning they have felt they needed to break backward compatibility dozens of times, and it’s likely your dependencies require conflicting versions just by accident of when they were written. I guess it’s because the maintainers live in a monorepo and just force any changes they need?
The other interesting corollary to this is: if your package relies on one like Guava, and it is not bumping its major version number every time it updates the version of Guava it depends on, then your package does not itself honor semver.
Much like libraries that run on Scala 2.11 or 2.12, I can imagine a system where I maintain several compatible minor versions (or named forks) of a library, each patched to use a different major version of Guava, and letting a caller solve for exactly which version of everything is compatible with everything else. But the more API churn we face, the harder this is.
Incompatible versions of transitive dependencies, incompatible libs that your web server added, this is the default in Java unless you pay close attention to your dependencies.
That wasn't my experience with Java back in the day.

What the article describes with Scala rings true, and I stopped using it (due to a job change) more than 2 years ago! So Scala was already going down this route 2 years ago.

> That wasn't my experience with Java back in the day

It is still not a typical experience. In our team, we try _very_ hard to avoid reflection and these errors are very very rare (never in Production).

Those sorts of java runtime errors largely depend on programmers' insistence on doing things via reflection, and it will be the same in any programming language: Like most drugs, at first reflection seems you've opened a new door into enlightenment, until eventually you find yourself sleeping in a gutter with half your teeth missing and wondering why it didn't work out as expected. A lot of Java open source is addicted to this stuff.

Scala just adds more drugs to the cocktail.

I don't think that this is entirely fair to Java programmers. Java's designers decided early on to lean fairly hard on reflection. Not just by giving Java strong reflective capabilities, but by sometimes deliberately choosing not to give Java great facilities for solving problems without using reflection.

When I first came to Java from .NET, I was initially shocked at how heavily it was used in the Java space. (.NET arguably has even more powerful reflection facilities than Java does, but they are typically avoided at all costs.) But it didn't take me very long to realize that many of the C# language features I would have chosen to use instead of reflection simply don't have equivalents in Java. So, I don't think that it's necessarily that Java developers are addicted to this stuff, so much as that they just haven't been given any other choice.

Java's type system supports code gen. See projects like the Checker framework or NullAway
The errors are created by failures on finding dependencies.
I only very rarely see this in Java, even in huge monoliths. Not that there's a technical reason for this; I think there's a cultural expectation that you don't break backwards compatibility with Java libraries. Perhaps the Scala world is more cutting-edge and fluid so there are different cultural expectations.

The OP mentions Jackson. Jackson 1.x -> 2.x changed the package (so they are wholly separate libraries), Jackson 2.x -> 3.x will do it again. I've never had backwards compatibility issues with Jackson. I don't know what someone could be doing in jackson-module-scala that breaks with a minor version bump.

Jackson doesn't have a stable API for building modules. You have to get elbow deep in their internals, which is already scary enough given that it's an old and highly performant library, but the bad part is that there's no formal commitment to maintaining compatibility. You just have to hope that the modules you use are popular enough that they will test them and make an effort not to break them. I've had an application break on a patch version bump of Jackson.
Java has the same dependency issues. But, from the article, it seems like there might be something cultural within the Scala community that contributes to the problem. Most Java libraries, in my experience, are relatively flat. The article gives an example of HikariCP, which depends on a random JDBC library from Akka. Obviously, that situation is going to end terribly given the popularity of Akka. As soon as Akka updates their library version, HikariCP has to as well or the two dependencies will get hopelessly out of sync. I don't know what `akka-persistence-jdbc ` does, but it can't be so important that it justifies the crazy dependency structure.
HikariCP is a Java library I thought, at least I’ve used it in many Java projects, so I’m not sure what that has to do with Scala.
Scala doesn't care about backwards compatibility. They break stuff all the time, And so major libraries are tenuously hanging on to whatever version they were targeted at. Akka prints out messages if it finds jars with even different minor versions.
Dependency conflicts is a fundamental issue of mature ecosystems, linux especially included.

The issue is one of granularity of dependency: it can't be calculated from the code and dependency graph easily. Each class or function invocation has an associated metadata version, and something that tracks all the sub-ones, with compatibility matrices across the major versions of the library?

As in, a dependency / linked library has a new version. How do you know if that can be safely updated in your code? All you have fundamentally is a coarse version number for the entire library, it's types/classes, it's functions/procedures/methods/signatures. Does anything indicate which signatures changed aside from compilers? Does anything mark which functions have new logic in them?

Yikes. That can't be maintained by humans. No language has dared to do something that would resolve to that level of compatibility analysis. Can you imagine the time involved?

Maybe there's simpler indicators. Git repo as a service might be able to use the repo history to track what parts of a library actually changed with some metadata file at a sufficiently granular level.

Currently, convention dictates that you use a new class name or namespace or something similar for "breaking" changes, or a major version number boost with some assumed "service life" for the previous library major version. You know, if they do that. But there's instances (one of the java bytcode emission libraries IIRC) where the api remainined the same but was a breaking change.

Nothing exists to help a library maintainer be aware of what will be a breaking change. At granular levels that is inherent to the language design. At best, you have unit tests as the actually deep introspection of the interface and expected responses. But that is per-project.

As mentioned, you can also shade and dynamically renamespace a library. That almost is the solution, but shared libraries are a thing, and a if you have 10 libraries each shaded-using a common util library (ahem, slf4j, first item in the blog post), then that's precious ram wasted, even in modern RAM sizes. With three-deep versions like 4.0.7 or something similar, how would a build system know that it could safely reuse a shaded version? It basically can't. There's no language constructs for saying that it can.

To some degree I believe this a failure, in the case of Java, of some sort of overarching organization that tracks commons libraries, and while maybe not placing them in the language standard library, recommending best practices around those libraries across known usage patterns so library import/compiling can be gradually optimized, or common conflicts alleviated. It's almost like security patching to some degree. Maven and its repos aren't up to the task.

You have a new language? Likely nothing in it will killer app it, instead what makes modern new languages succeed isn't just novel language features, it's community and herding cats. It's what Zig just learned from one tweet, what Lisp's community never really learned for what otherwise should be the "ultimate" language. It's how Rust has made progress, and maybe Go too.

I wonder if in 200 years if there will actually be mature, stable languages with mature, stable libraries that haven't needed to change for a couple decades.

Anyway, "compatibility" is a hard hard hard problem.

Dependency management is painful almost everywhere. I see a glimmer of hope for the future in Unison, a language in which code exists as content-addressed ASTs. Dependency version conflicts cannot exist; there is not even a need to resolve a set of dependency versions.

https://www.unison-lang.org/learn/the-big-idea/

One thing is Scala plays fast and loose with backwards compatibility. So much so that akka actually prints out messages if they find jars with different versions. It's a pain in the arse.
A good middleground is Kotlin. You get some of the nice features / syntax from Java without the problems. While Scala is actually a way more powerful language, Kotlin is more than good enough for most real world tasks and the tooling is so much better.
Exactly, you might even go as far as to say that Kotlin exists because the people at Jetbrains looked at and dismissed Scala as just not what they were looking for in a language. And then they went on to develop Kotlin instead.

Kotlin is unique in the sense that the language originated from a company whose primary business it is to provide developer tooling and IDEs (intellij). They know a thing or two about what developers like and appreciate in their products.

It shows. This language is very nice to use for programmers. Lot's of clever syntax that minimizes boiler plate. Lot's of clever IDE support. Lot's of convenient features. Good build tooling. And so on. In contrast, Scala was always a bit all over the place. Lot's of different takes on how to do things; not all of them very successful in retrospect, tooling was a bit iffy, and so on.

It's the reason Kotlin got popular with Android developers early on because it provided a massive improvement over plain Java and sort of worked as a drop in replacement and was easy to switch to. As soon as Kotlin became available (pre 1.0), the Android community was all over it because at the time they were stuck with a pretty outdated Java language version. It did not take long for Google to make it the language of choice and start providing lot's of Kotlin focused updates to their SDK.

For the same reason, it got popular with Java backend developers early on. It doesn't really matter what Java backend framework you use; Kotlin is a drop in replacement for Java and the chances are pretty good that your framework of choice already has extensive Kotlin support in the form of Kotlin DSLs, extension functions, etc. That's certainly true for Spring/Spring Boot, Quarkus, and most other mainstream server side Java frameworks you can name.

The comparison with Scala is fair because a lot of Kotlin libraries are inspired by work in the Scala community. Additionally, it seems a lot of former Scala developers are now doing a lot of Kotlin. For better or for worse, it seems to compete pretty effectively with Scala. Either language of course is a pretty big improvement over Java; even with the improvements that Oracle has been trickling in over the last few years.

> They know a thing or two about what developers like and appreciate in their products.

Hah, I wish that was true. Looking at the last releases and the new UI which is about to come I highly doubt that is true. Although adding flashy new features instead of fixing bugs in a "visual" IDE is different than developing a programming language.

What do you mean exactly with "the last release"? I think Kotlin is on a good way and JetBrains is investing in the right things like the new compiler. There are also a lot of low-hanging fruits in the Kotlin YouTrack issue tracker, but then again I accept that is better to focus on fundamental things like the compiler where every developer profits from.
It actually is. Now that IntelliJ has cut ties with the Evil Empire I would expect its adoption to grow faster. But I must say that a year ago I could find no Kotlin _backend_ positions in the Bay Area.

On the technical side

* I don't like the idiomatic Kotlin approach to concurrency. Its coroutines are more difficult and unusual than typical Future-based libraries in other JVM languages.

* I'm not convinced null safety is a big enough question to justify multiple cryptic operators.

Personally I dread the demise of Scala. The Haskell lovers and the Akka license changers are certainly squeezing regular developers out big time. Databricks built a C++ engine, Rust is increasingly popular in other new OSS query engines. Those trends don't bode well at at all. Java is more expressive than golang but I'd rather use something more modern than either of them.

> I'm not convinced null safety is a big enough question to justify multiple cryptic operators.

I am. I've been working on a large c++ project recently and almost all the crashes in it would be solved by compiler- enforced null safety. Kotlin's null-safe operators don't look cryptic to me, they're more or the less the same as those from C#, Typescript etc. OTOH Java seems to go out of its way to make it hard to write null-safe code.

Honestly Java is lately the best it's ever been, at least for backend services. So much power in the frameworks (ok Spring Boot) with so many powerful libraries and tools and available apis.

You really feel like you can do anything with it lately.

This guy loves sbt. For me it's one of the main reasons to use TypeScript instead of Scala.js. npm is so much better. I have been writing a lot of code in Scala.js and Scala about a decade ago, but thinking now of it, I feel only dread. Scala the language is nice enough, but the whole ecosystem around it is so stuffy.
Give Mill a try.

You need to realize the Scala ecosystem is not monolithic. Things are mostly fine if you stay within a corner, but can get complicated when you start mixing dependencies from multiple domains. I think that is true for many languages. The JVM ecosystem is rich, and that comes at a price.

Oh, didn't hear of it, interesting.

But anyway, I am focusing on the browser these days, and a Scala.js that a) doesn't interoperate with TypeScript b) doesn't allow me to author npm packages is too much of a hassle.

Seconded. Mill is a very versatile build tool. It mainly focuses around modeling builds as DAGs of tasks, and thus allows you to only rerun what is necessary after changes. Other tools like Bazel are built around this model too, but IMO Mill has "taste" in the way it is configured. It also gets out of your way, you can seamlessly integrate it into various shell scripts, and you don't need to make your project revolve around your build tool.
I yearn for maven after having to use sbt the past few years.
Now I just miss Rust when writing Scala.
Kotlin is a fine middle ground. I would say that coroutines was a misstep (though that's a matter of taste), but otherwise their choices have been pragmatic, and their multiplatform efforts are impressive.
Yeah, the interop makes Kotlin also a hundred times easier to test out. No changes to setup or tooling, just drop a few lines in your pom.xml and you're good to go.

But curious, what's wrong with the coroutines? For some projects I've found them a nice abstraction when you have lots of IO-bound tasks, and they're bound at various places in the code making use of a single executor+threads/tasks hard to scale.

> But curious, what's wrong with the coroutines?

Maybe I need to revisit them, as I've only used them (on 1.6) in the context of kotlinjs (which has a limited implementation) so perhaps my impression is flawed. That said, I didn't like how viral they are in the codebase. In an executor/thread paradigm, you can box up the asynchronous behavior quite cleanly; in a codebase that uses coroutines, I ended up propagating `suspend fun` up and back in my codebase.

Ah, yes. The "which color is your function" is a bit problematic, but nothing inherit to Kotlin's approach I feel. I'm having the same issues in an asyncio python project now, for instance.
I am so happy Java chose not to color functions with its implementation.
Which implementation? Does java have coroutines now? Or do you mean green threads / loom?
Virtual Threads/Loom.
I drop scala into old maven projects all the time by dropping in the scala maven plugin
They have to be careful, there are tendencies to over-complicate things as well. I hope coroutines will die on the serve side once JVM Fibers are widely available.
Coroutines for async IO will hopefully die, but right now coroutines are the best way to implement continuations, so I hope they just become a niche feature for library authors to do things like monad comprehensions, etc. I can also imagine nice DSL-ish APIs for things like SQL transactions, where you can call "rollback()" to abort the transaction inside a closure, instead of throwing an exception and catch-swallowing it.
Is Kotlin too much tied to maven? Can someone be productive with having to do maven hair splitting.
Gradle is the default for Kotlin projects.
Every Kotlin project I see uses Gradle. I still prefer maven though.
I disagree. Obviously, this is all just subjective preference and opinion, so parent should not take this as me saying they're wrong.

I hate Kotlin's "middle ground" approach.

Scala has persistent data structures for collections, which means that non-destructive updates and copies are cheap. This is great for an immutable-first approach. Kotlin uses Java's mutable collections, so all of the standard APIs in Kotlin make full copies. Sometimes it might even be surprising where copies are made. For example: `listOf(1, 2, 3).toList()` makes a copy of the list instead of just returning it. To understand why this is necessary, see my next point.

Scala's mutable collections are NOT sub-types of its immutable collections. In Kotlin, there is no such thing as an immutable collection interface. You have MutableList and List, but despite the confusing naming, List is NOT immutable because MutableList is a sub-type of List. So any time you write a function that takes a List parameter, you can't assume that it's not actually being mutated from another thread while your function is running. That means that you technically can't even assume a List is non-empty after you check `if (l.isNotEmpty()) { useElement(l[0]) /* this might crash */ }`.

So Kotlin's middle ground approach means that it's inefficient to use the pseudo-functional APIs and its collection types are not concurrency-safe.

Then, there's no error handling mechanism in the language. Well, there's throwing unchecked exceptions. But the Kotlin team tells you not to do that. They tell you not to do that, but that's actually the only thing that is done in the standard library, the kotlinx.libraries, and every single thing that IntelliJ actually publishes. So, it's very "do as I say" with no examples. At least in Scala we have Try, Either, and "for-comprehensions" (a.k.a. monad comprehension, do-notation, etc). Kotlin "recommends" we use sum types to express failures, but without monad comprehensions, it's extremely awkward and verbose, so I've literally never encountered a Kotlin library in the wild that does anything but throw exceptions for business logic failures. I strongly believe that it was precisely to avoid scaring off Java devs that they didn't do do-notation and monadic error handling.

I don't mind colored functions. I do absolutely HATE that Kotlin coroutines use exceptions for control flow and business logic. It's so hard to correctly handle sub-jobs in coroutines in any non-trivial case with cancellations, etc.

They also decided to not do type-classes, so we get half-baked, ad-hoc, cherry-picked type-class-like features such as extension functions and multi-receivers. I especially dislike extension functions because the receiver is resolved statically (it has to because of how it works under the hood), which is NOT the way regular method calls work, which adds yet another inconsistency to the language that's impossible to catch at compile time.

Ugh. And I'm working on Kotlin code today, so now I've got myself all upset about it. lol.

> the ecosystem is essentially a microcosm of the US political landscape

what does this mean?

It's hard to answer meaningfully without risking starting a pointless debate in the comments or being fully honest, but I will try:

There are two FP ecosystems inside the Scala community with a very adversarial relationship towards each other. The root is that many years ago the lead developer of one of those FP communities allowed (based on community feedback) a speaker to give a technical talk. There were some people demanding that he'd be cancelled based on his right-wing views. This evolved into a full-blown conflict with serious accusations over the years about political alignment.

I am not a member of the Scala community but are interested on the language and somehow this conflict kept popping up. I agree with the author about the "US political landscape" microcosm: the conflict felt absurd and completely blown-out of proportion to me as an european.

Note this all happened years ago and thankfully the community has very much moved on.

Travis one of the guys involved has even left Scala to do his activism work full-time.

I don't think the community was allowed to move on. JdG has repeatedly behaved like an asshole and poured fuel on the fire with Typelevel people who never cared about that original LambdaConf drama and his feud with Travis. Instead of moving on, he decided to make more ennemies, to the point several library maintainers don't want to touch anything even remotely related to Zio.
Difficult. I will attempt to answer this in a way that won't upset people and may be informative?

Here are two ways of looking at it:

a. People in the USA* have massive fights about things that no-else cares about, and software projects put up a statement about those. This is off-putting to everyone else.

b. The USA is ahead of the curve on some political movements, and the article is expressing conservatism/anti-conservatism/a reaction towards being expected to act according to morals that aren't majority accepted in their country yet.

To decide for each particular movement whether it's (a) the wave of the future or (b) a passing fad? Who can say? You are supposedly an autonomous moral being, so use your own judgement.

*This is true of any place and any people, but everyone else has to put up with the USA's quirks because rich influential explosives. You could substitute Twitter for the USA here. Hey, who gave Twitter all those stealth bombers?

I think the short answer is that the US is the dominant soft global empire (which is to say this is not merely military, but also economic and cultural). What happens in Rome ripples outward into the broader realm.

But I also believe that another contributing factor is that Americans, regardless of political affiliation, often demonstrate a presumption that their own provincial squabbles, concerns, and anxieties are shared by everyone else on the planet. This is not categorically unique to Americans, but such presumption is reinforced by boorish imperial egocentrism.

And, of course, some people simply don't have the sense, consideration, and social grace to know what the appropriate time, place, and means are for expressing political convictions, and as a result, obsessively pollute all manner of social interaction with the aforementioned topics.

constant drama.

Travis Brown (a very sociopathic and toxic, straight up unstable person) tried to cancel John A De Goes, total shitshow ensued. FYI, Travis has created scripts to auto-dox people on Twitter if he doesn't like them. Travis also left Scala ecosystem after lashing out at literally everybody including Martin Odersky

Reason: De Goes invited a speaker to his LambdaConf conference, without knowing that speaker was involved in white nationalism (US). I don't remember the exact details, but it was a huge scandal

De Goes tried to reason that all kinds of people should be included in the tech conferences irrespective of their political background. Being stubborn as he is, I don't think he ever apologised. De Goes was later booted from cats project, one of the reasons why he started Zio.

IMO De Goes is a great project leader still, and many Scala devs are moving to Zio.

I might be misremembering but wasn't there a pro slavery angle as well?
Jesus. Yeah, I will stay with TypeScript.
Keep on posting. Me waiting for season 2.
You're joking but this stuff has been going on for longer than most Netflix shows :D
small edit: JDG did not invite the speaker, they applied to an anonymous call for papers, once it was accepted, it was later revealed he was Moldbug. JDG, after polling other under represented speakers, decided not to rescind the invitation.
I actually think Scala is in the best position it's ever been.

There is a commitment to making the language simpler, easier and cleaner.

On the backend, ZIO (https://zio.dev) is the best concurrency library on any platform. On the frontend you have really interesting Scala.js projects like Laminar (https://laminar.dev).

The biggest issue really is the tooling. SBT is simply awful.

On any platform?
It has the ability to make real-world concurrency scenarios trivial e.g.

* 3 fibers - each fetches from remote storage, local storage and in-memory cache.

* Race them, kill the two slowest and give me the result.

* Free the resources safely including if any of the connections fails for an unforeseen reason.

That's a few lines in ZIO. Pain to get working properly in Java, Rust, Go, C++ at least.

This is exactly the kind of problem that 0.000324% of us are having while being productive in Java/Rust/Go/C++ ... ;)
Thats the thing with Scala, they are solving important problems. It is not spending time on useless problem like performant build system. I mean code is gonna compile eventually, if not today maybe tomorrow. But complex problem like described above will not be solved unless someone make a decent framework for it.
In the last 10 years every team/company I have been working in had to deal with at least one of these problems. Good for you if you only ever have to work with single threaded applications, but for most of us the reality of modern software development is different.
It definitely is. You can even see it by looking at how the languages market themselves, claiming to make concurrency easy etc.
This is actually trivial in Go as well, with a context (cancellation) and a WaitGroup or channel (waiting for the first one to finish).
Go fails at the error-handling and resource-safety part. The compiler does not cover you properly.
The fact that the compiler doesn't cover that automatically doesn't mean Go fails at it, as it has very good primitives for handling them.

Error handling and deferring for resource closure work just fine.

Sure you could say "but the compiler doesn't guarantee it". But that's not much of a point if it's not a real problem in practice.

> The fact that the compiler doesn't cover that automatically doesn't mean Go fails at it

But that's exactly what OP was talking about. Maybe for you that doesn't mean Go fails here, but for (us) Scala developers it definitely feel like Go fails us. We want a language that fails at compiletime in as many cases as possible.

> But that's not much of a point if it's not a real problem in practice.

Maybe not for you. For me it is!

I agree it's fine to have different taste, as I mentioned in another reply to you.

But it's the difference between whether this statement is objective, or subjective.

> is the best concurrency library on any platform

Fair enough, that sentence is a bit over the top. I personally agree, but it is subjective and sounds like a fact.
Error handling and Go doesn’t mix well.
That's a matter of opinion. Many, me included, very much like the current, very explicit, approach.

I understand why people who like monadic constructs don't like it though.

I don’t know — I don’t claim that algebraic datatypes are the only proper way to handle errors, I’m okay with exceptions as well (even checked ones). But what go has is only very slightly better than C’s attempt, so I’m not sure it is that subjective.
I think the presence of multiple return values and the ability to easily use complex types for errors make a huge difference (adding wrapping messages, context, etc.).

I agree algebraic data types could improve this. I don't think monadic result types or exceptions would be an improvement.

Not a real problem in practice is just another way of saying rare. But given enough scale and enough time, rare things do happen, and they cost inordinately more programmer effort to chase down. I actually don’t mind if the compiler lets me ship very dumb bugs: those will be auto-rolled back out of production in seconds. It’s the subtle stuff that kills me.
I think maybe you've misread the intent.

I do not want to wait for the three fibers to finish. I want the whole process to stop the minute any of them have returned i.e. get me my data as quick as possible no matter its source.

I haven't.

You wait for the first result using i.e. a shared result channel, then you cancel the context.

It's still error prone in golang. Java's structured concurrency approach is much better.
It may be the best on any platform outside of the BEAM, but there are a lot of correlating factors needed to create the ideal concurrency platform that you simply can't do without building them from the ground up.

It's why almost anything outside the BEAM can't make that claim.

True, BEAM is a platform on its own. Scala can use Akka which is also awesome, but doesn't have all the nice things builtin like BEAM.

I guess a merge of Scala as the language (because honestly, Erlang & co suck) and BEAM as the platform would be awesome!

A statically-typed language running on BEAM? Sounds like Gleam: https://gleam.run/

(Disclaimer: I haven't used Gleam, I just know it exists.)

I think as a Scala developer, my expectations/demands can't be matched by Gleam unfortunately. But if it could, then yes!
I find that one of the best things about using a managed runtime such as the JVM is the ability to get stack traces when things go wrong. When debugging, it is a considerable time saver to be able to determine the causality chain that lead to a specific failure.

Unfortunately, all libraries that abstract concurrency on an application-level break the ability to get meaningful stack traces. At least all the ones I know of, including ZIO, Akka, Monix, plain Futures, etc. I know that there is tooling to counteract that (such as the abstractions used in distributed tracing), but that's again on the language level.

In my experience, for all but the most advanced applications, the debuggability advantages of using linear code outweigh the performance advantages gained by abstracting over execution contexts. Thus, I would posit that concurrency is best dealt with on the platform, not the language level, especially when starting a project.

Of course there are some situations where a library can make some concurrency task appear trivial, but as long as there is no good tooling, the time saved using beautiful abstractions tends to be paid back 5-fold when those abstraction break (which they often do as an application grows).

> Unfortunately, all libraries that abstract concurrency on an application-level break the ability to get meaningful stack traces.

This is completely false. Years ago we (7mind) added async stack traces to ZIO. Now both Cats and ZIO support them.

It's trivial in Haskell, a bit hard in Rust, really hard in Java, and trivial to get a non-working implementation and declare it flawless on C++. I never tried it in Go.
I agree with a lot of the criticism in the article, but also agree with this idea that Scala is in the best position it has ever been. Core Scala is migrating to Scala3 (will take a few years) and the scala team had the courage to take on the rough edges. The Typelevel community (FP side) has a whole ecosystem which is maturing into something really nice. Akka pulled the ripcord on licensing so everyone knows where they stand.

Across the board the language and environment is stabilizing. Most of the (correct) criticisms expressed in this article are either 1. An expression that dependency management remains really hard as dependencies and ecosystems grow 2. An artifact of the fact that early scala projects relied heavily on borrowing from java to bootstrap and it caused a snarl of dependencies. On the latter, I see a decline in snarl overtime.

It is fair to say that Rust and Go have a really awesome toolchain experience and are setting the standard (though I wonder if the problems of being "old" and having boatloads of libraries haven't yet set in). SBT nominally has a similar experience but it's definitely slower and somehow less intuitive. Hoping to see more work in this area and I think Mill + SBT "competing" + BSP and bloop opening the door for more innovation will allow for quick progress.

For me the big win with Go, is its so easy to get from new project -> first working test.

I think there installation of the required tooling is very easy and just works, unlike other languages where you can spend a lot of time just getting all of that initial stuff setup. Also upgrading the tool chain is very easy as well.

That's funny, because this is what I really like about Scala; how quick and easy it is to get a project started.

> sbt new scala/scala3.g8

will just create an empty project. If you don't even want to bother with a project, use use scala-cli or ammonite (http://ammonite.io/) to just start banging out code.

Even the upgrading of a project from Scala2 to Scala3 is a breeze, thanks to very good backwards compatibility of new library releases.

> The biggest issue really is the tooling. SBT is simply awful.

It's like they sat down and said "Maven has a bunch of problems. Let's fix none of them and introduce a few new ones."

Agreed. Maybe the situation has changed now, but it also didn't help that sbt's DSL is so inconsistent.

Back 2 years ago, when I still used Scala, sbt had two ways to write build files, the "old" and "new" ways, both non-trivial except for the simplest cases, and when you were troubleshooting/debugging problems with your build, all the answers you found googling were for the other style (facepalm).

What kills me is IJ underlines all my sbt files in red.
Ouch.

I remember back when Scala was still on version 1, the official/recommended IDE was Scala IDE, based on Eclipse. Eclipse was already a mess at that time, and people were abandoning it in droves even for Java work, but (bizarrely) Scala IDE was endorsed by Odersky.

Get this: refactoring -- critical for a language like Scala -- was totally broken on Scala IDE. Completely, unusably broken. Like, you changed the name of a function and the IDE inserted nonsensical garbage that didn't compile or even follow syntax rules everywhere. This situation went for long enough that most sane people migrated to IntelliJ. This was back then, no idea what the situation is now or whether Scala IDE still exists.

I recommend to have a look at Mill. It's versatile, built on simple foundations, and implements many concepts from general-purpose build tools such as Bazel (but of course it was designed for Scala). It's easy to call it from various scripts too, and doesn't require you to design your project around your build tool.

At work we've used mill to first replace sbt and then also gradle in another project, and haven't looked back. It worked out-of-the-box for our JVM projects, and we trivially wrote custom "rules" for integrating cmake-based C++ projects into the build.

Sometimes when creating software that solves a hard problem, the author is so thrilled by all the little conceptual breakthroughs they experience along the way that they think the users of their software will enjoy it just as much as they did, so they write the software in such a way that the users have to make all the same conceptual breakthroughs in order to use it. SBT feels like that's what happened to it. It's completely inappropriate for a build tool. 99% of the people using a build tool shouldn't have to appreciate how hard it is to write a build tool.
Big agreement here.

Scala2 was a wonderful language, Scala 3 even more so; lots of corner cases have been removed and I even start to like the significant-whitespace-style.

ZIO and Typesafe (although I agree with the article; I could do with less drama) are simply amazing ecosystems. Libraries like Tapir and Quill seek their equal in other languages.

And even though sbt could be better it has been vastly improved in the last few years.

granted ZIO is excellent.

Scala.js is a dead end that almost no one should be investing in. Who can honestly say that the best possible dev path for them (product/business) is to need Scala devs to do their JS frontend? Even just the economics of the pay-gap in those two skillsets is untenable. We've been through this before any number of times in JAVA, give up it's an awful choice no one will thank you for.

I'm also frustrated by how we seem to have managed to not only recreate the Spring problem with FP libraries (communities online will tell people to first go with their personal FP lib of choice as a "must have" for starting a project) but make it worse by also having competing 'factions' who argue about which one is better.

We're apparently aiming to recreate all the same mistakes JAVA started making which was the launchpad for Scala and other JVM language variants in the first place.

I sincerely hope Scala.js isn't "dead". Though I know use by academics isn't the use case you imagined, Scala.js has very much been the right choice for me publishing interactive Open Educational Resources that can include all sorts of little simulations, models, and programmable games. It's not the sort of thing I'd have time to do in any other language, but via Scala.js (and a front end framework I wrote) I can put together something that (though it's scrappy because I rarely get time to add the polish) works well enough very fast.
> We've been through this before any number of times in JAVA, give up it's an awful choice no one will thank you for.

Is it? Google uses it quite extensively, though they mostly have their shared business code in the form of a java library that is compiled to each target platform.

Disclaimer I'm already a big fan of Scala, but I agree that the tooling around scala.js is lacking and the std lib is a rather large blob to ship around, especially when compared to alternative functional languages like ocaml.

However, I've been using the above mentioned laminar for my personal frontend project needs and it really is a unique approach to the 'reactive' frontend with no vdom actually using reactive streams to track what needs to be updated. The dsl is easy to read and write and i can actually read the underlying code. For me it's scaled well too large datasets generating svgs. I think it's worth the scala.js barrier to entry.

> Who can honestly say that the best possible dev path for them (product/business) is to need Scala devs to do their JS frontend?

The ability to give a developer a feature and have them use the same language, domain model, error handling logic, business logic, serialisation codecs, tooling etc to implement it end-to-end is compelling to me.

And the number of developers who are seriously good at full-stack is far smaller than Scala ones.

> The biggest issue really is the tooling. SBT is simply awful.

This is backwards. The problem is that scala is simply awful. SBT just reflects the problems with scala. First and foremost, the authors of the scala language are either incapable of writing a decent build tool or they think that SBT is good enough. They have proven over many years that they do not prioritize the experience of developers actually writing code. Slow compile times are a much bigger drain on productivity than the superficial syntactical improvements that were made for scala 3.

The specific problems with sbt, needless complexity, inscrutable dsls, bloated code paths leading to slow start up times: these are all endemic to scala itself. The standard library is so badly organized that it takes 100s of milliseconds to load a simple hello world application: https://twitter.com/li_haoyi/status/1125674970829320193?cxt=.... Mill may be better than sbt in some ways, it's definitely worse in others but at the end of the day, if you are using either, you are stuck with scala and scala is very, very unlikely to ever get significantly better than it is today.

I wrote scala for six years and was on the team to first deploy akka in production. I've seen Json libraries come and go while also struggling to read files written with OO and FP patterns intermixed. Scala can be beautiful but in practice it gets messy.

Switched to Go four years ago and I've never looked back. Go made programming fun again just like PHP did before either of them.

Still here having fun with PHP :)

PHP 8.2 isn't Haskell but the type system is reliable and usable. There are a few gotchas here and there, almost always due to backwards compatibility, but nothing like earlier versions, and IMHO not more than other popular languages.

No, PHP since 5.3 is just pseudo Java.
(comment deleted)
hmm, did we work together then? :) Always thought I was on the first team to deploy Akka in production.
to be fair, using Akka was mostly never fun, avoiding that improves the scala experience dramatically.
I was part of a team that processed really large files (hundereds of GB) in an Akka cluster. At that time Akka seemed like a clever choice to us, since we were Scala enthusiats and Akka was the framework of the day, but it took us many weeks to master (more or less) Akka. We could have done the same in a more robust and manageable way with Spring Batch in a fraction of the time.

Akka had a really steep learning curve for doing relatively boring things. Technically it was quite interesting, a from a business perspective it was a desaster.

> Scala can be beautiful but in practice it gets messy.

And, of course, you have a peer-reviewed article to support your statement?

> Switched to Go four years ago and I've never looked back. Go made programming fun again just like PHP did before either of them.

My guess is this due to being actually be able to focus on the problem, instead of being distracted by type systems, language features, and deciding which of those features would actually be good to solve the problem?

If yes, then I would feel the same. Problem solving is the fun part of coding, and it makes me happy whenever I reach my actual goal - with whatever language is used. Being able to play around with language features to solve a problem mroe efficiently or elegantly can be fun too. But it's often more so if one is the original author of that software. If one is just a contributor then having to learn and understand extra technology that distracts one from actually solving the deemed problem can make tasks a lot less fun.

> I’m also having affectionate memories of JavaScript and Python

I am afraid, things are equally messy in JavaScript and Python too. "X language isn't fun anymore" is exactly how I feel about X = JavaScript, X = Python, X = C++, X = Java and many other languages.

There was a time when I found Python and Js to be very fun languages. But recently the ecosystem has been becoming a mess. Build breakages on dependency upgrades are the biggest fun-killer IMHO.

Heck, there was a time when I found even Java to be fun. C++ too was fun in its early days. But every language keeps adding more syntax, more complexity and more ideas that deviate from the original design goals of these languages. These additions make the languages messy and the simple and characteristic ideas for which the languages were once loved get lost in all the complexity. I find it really disappointing. I really wish the languages preserved their original culture and philosophy.

For the never-ending and ever-increasing churn in all the languages I have gradually gone back to adopting Emacs Lisp and Common Lisp for all my personal programming needs. Common Lisp's standard is frozen in time, so for better or worse, I am protected from the constant churn I see in other languages. Emacs Lisp has a really good leadership that has been very wise to avoid adding additional complexity to the language. I wish the more modern languages were more reluctant in adding new complex ideas into the languages.

Even Markdown is further distorted the more time passes (and it isn't even a programming language).
How so? I only use basic markdown (e.g. for ReadMes and quick note taking), so I'm fairly ignorant.
Yes, but some 'central' agencies push for specific Markdown formats/use. E.g. Nextcloud [1] wants to use Markdown as a format, to save the output of their wysiwyg text editor. Everytime you open a Markdown file in nextcloud-text, it is 'formatted' correctly, according to the Commonmark specs, and written back, _without_ asking the user.

[1]: https://github.com/nextcloud/text/issues/593

> I really wish the languages preserved their original culture and philosophy.

You mention a couple of lisps as being similar to this. I wonder if there is any more programming languages that could be considered complete? Forth? C? ASL?

ANSI C and SML probably qualify, though I hope you don’t need utf-8
You probably won't write any useful and nontrivial piece of software in C today without using external libraries, so if you really need Unicode, you will probably use one one of Unicode libs - although basic operations like copying will work without these anyway.
I think Lua is a good example. It has stayed simple and avoided change because of its position as an embedded language and strong leadership. Another good one would be Smalltalk.
Yeah, definitely Lua.
I couldn't tell you exactly why (though I have some ideas), but Lisps seem to settle into amazingly stable languages. Even Clojure, with all its initial trendiness, has been remarkably resistant to bloat and churn. Such things as it's added have largely been either standardisations of things that people were doing anyway, or very natural extensions of ideas that were already there, and it still generally passes the "compile X year old code" test.
> I couldn't tell you exactly why (though I have some ideas), but Lisps seem to settle into amazingly stable languages. Even Clojure, with all its initial trendiness, has been remarkably resistant to bloat and churn.

I would say that the core reasons are well understood:

1) The fact that there is built-in syntactical stability in any Lisp since the code must comprise valid Lisp data structures + a couple of special symbols.

2) The second reason has to do with the fact that Lisp macros allow language extensions directly by users, provided those extensions comply with fact 1. When users can extend the programming language by adding libraries, there is little reason for the programming language designers to chase every trend in language design, ending up with the kitchen sink—sorry "multi-paradigm"—languages of today. The core stays small.

Amusingly, point #2 brings its own set of complainers because they once had a bad experience with C macros.
Clojure has massive amounts of ecosystem and toolchain pain, even though it is a cool language. Most common dev environment for it is a complex emacs tool chain. If you are seeking the simple joys of programming, Clojure is unlikely to be what you want.
I beg the differ. Setting up a Clojure deps environment requires like one file, want a REPL to connect to your editor? Usually add one/two lines to the deps.edn file + install the extension for your editor.

The ecosystem also has a huge emphasis on backwards compatibility and finishing libraries rather than the constant churn you see in other ecosystems. I can usually find a 5 year old Clojure library and include in my project without any problems at all, and when a major library want to try out an idea that changes the interface, they usually start a new library instead of forcing everyone to use the new interface they've come up with.

I'd say if you're seeking simplicity in terms of environment and programming, Clojure is definitely the way to go. And this is coming from someone who knew 0% Java coding before jumping into Clojure, and almost never touch/read any Java code when doing Clojure programming.

> Most common dev environment for it is a complex emacs tool chain.

IntelliJ + Cursive is not far behind. From the 2021 Clojure survey 43% of the devs were on Emacs and 31% on IntelliJ/Cursive. Then 12% VS Code etc.

Anyway I don't think an Emacs setup to develop in Clojure is that complex. I'm using Emacs with both Cider and LSP: doesn't strike me as particularly complicated to set up. If you're familiar at all with Emacs, it's pretty straightforward to configure.

If you're not familiar with Emacs, you can use IntelliJ with the Cursive plugin: apparently as much as one third of all the Clojure dev opt for that setup.

As a sidenote apparently 52% of the Clojure devs are on OS X and "only" 37% on Linux.

Clojure with VSCode (with the Calva extension) is a breeze.
setup and emacs were quite simple for me - for emacs I just installed clojure-mode and cider via melpa like any other package. I think later I added paredit. All should include snippets for your emacs init file on their github project pages.

When you have a project source file open you can M-x `cider-jack-in` (or C-c C-x j j) to open a fresh repl right in emacs. I found this useful advice for after cider and clojure mode are installed (skip the “configuration” section) - https://www.braveclojure.com/basic-emacs/

Setup on the Clojure/filesystem/JVM side was just leiningen - install lein and then `lein new app foo` gives you a fresh project dir for `foo`. You should probably install lein before the emacs stuff as cider may need a working Clojure install, not sure.

I don't believe this assessment comes from a professional Clojurist. Emacs is common but not necessary -- you can easily reach for Calva in Visual Studio Code. Leiningen provides a tested and very accessible build environment. But I prefer the Cognitect tools deps toolchain instead, which does have a larger learning curve. Again, the developer can choose. The author and many in the comments decry JSON parsing pain in Scala. JSON is handled elegantly in Clojure -- while Jackson (neatly wrapped by Cheshire) has its occasional CVEs to wrangle, you can instead employ clojure.data.json which is performant and free of Java transitive dependency bloat and CVE surface. The transitive dependency hell mentioned in the article seems to be exacerbated by Scala tooling, though Java inter-dependencies can be complex and difficult to manage in any JVM language. I have found Clojure's tools deps toolchain to give the most elegant dependency management experience I have experienced on the JVM.
> Lisps seem to settle into amazingly stable language

Lisps are built around being a simple base supporting in-language extensibility (it's the killer feature that has kept it alive as a language family, and there is lots of experience with how to do it in Lisp which means new Lisps tend to get it right from the start), which means that there is relatively little reason to break it to add features, you just build on top.

Of course, the downside of that is that it is very common for projects to have lots of code in what amounts to a project-specific DSL that is both close enough to be confused with and different enough for that confusion to be dangerous compared to how any other project does many of the same things.

Python is still a lot of fun in certain areas:

- machine learning, because AI is fun, and it's very easy to play with it in python. Also because you can easily stitch services together that allow you to make cool apps without having to code the hard part, like creating a discord bot to talk to midjourney.

- anything that will use pydantic and type hints to generate parsing and validation. Fastapi, typer, etc. It's really a blast to just define types, and see your web api take off.

But it is to be expected that when something has reached a critical mass, it becomes banal, and therefore not exciting anymore.

Also, the Python ecosystem and resources have accumulated a lot of legacy stuff, and has been flooded with new comers content, so the noise to signal ratio is not great these days.

I though as a python expert I would be less relevant given the number of new devs entering the market. Boy was I wrong. It just feel like having a cheat code to ask for more money to my clients, by the sheer amount of things I learned because I was there 15 years ago.

The dependency thing is a good example. Dependencies is in actually a better state that it used to be, but because there is so much noise, very few people can enjoy it because they would have to setup python in "the right way" to do so. However, unless one invests a huge amount of time in looking up for this right way, filtering all the noise is going to be impossible. Hence most people have a broken python setup, and when they try to install something, it has a high chance of breaking.

Of course, technical dept, and our inability to pay it back as a community, doesn't help.

What's the cliff notes of the right way / where's the signal in noise?

I don't write Python, but Python is like Java these days, it finds you.

In short, a huge number of packaging problems come not from packaging, but from the way you install, configure and call python. Unfortunatly, everybody and their mother tell you how to do this, and you'll find 1000 articles to get you in trouble, but very few to tell you what you should actually do.

The full story is pretty long and most people don't have the time and resources to learn everything about it.

The easiest way is to follow a receipe for the least pain possible, which includes limiting yourself to a single path for bootstrapping python. Here is the one I currently recommend to my teams at the end of the comment:

https://news.ycombinator.com/item?id=32805483#32807220

It can't solve as much as knowing the whole deal, but it will remove a lot of ways to shoot yourself in the foot, and work around a lot of the legacy issues. And above all, it's easy to keep around and to apply. I noticed that anything more complicated will lead to people, so I removed a lot of things from it years after years (like -m, pipx, etc).

Of course, this will not solve the setup that are already in place, which you will likely have. I can't provide a generic way to solve that, there are too many possibilities.

Hopefully the community will eventually solve most of this by providing better default in the future, but this is an excrutiatingly slow process.

My impression is Python packaging is stuck in a local maximum, and that any attempt to move out of it will be as disruptive as 2->3. Dropping support for conda et al will only split the ecosystem, hasten the rise of Julia, and make Python packaging more acrimonious. I like your simplified approach (and take a similar approach where I can), but much of the value of Python comes from its ability to be inserted without too much fuss (assuming you'd build things from source) into an existing system. I'd suggest while wheels were a good idea at the time, they've become a parallel ecosystem and source of division.
Not at all.

As I said, most packaging problems don't come from packaging itself, but for bootstrapping. Symptoms from a terrible bootstrapping situation creep up and they come out in packaging.

Unfortunaly the solution is of the worst nature possible for a FOSS project, because not technical: it's policital. This is the kryptonite of volunteer efforts.

The community has to get organised around one way to install, configure and run python. But it's really hard to do, and requires to synchronized a lot of different group of people, efforts, and make sure everyone are on the same page.

E.G, of a single point:

To chose which version of python to run, the installer for windows provides the "py" command, anaconda provides the conda prompt, but the windows store provides a suffixed command like most unix do. Most people are not aware of those differences, and when they attempt to follow a tutorial that has been written by somebody knowing only one of those combinations, the person will fail. Either with a "command not found", a broken install, "import error", a "syntax error" or installing things for one version of python and running the other version by mistake.

This will lead the person to believe packaging is broken, while it's not. The way we install and run python is broken.

But how do you solve this problem? By engaging in a long, frustrating and thankless talk with each of the parties involved. There will be debates, people will talk about taste, diversity, backward compatibility and so on. It will be a nightmare.

The alternative would be for the core devs to come up with a single recommended setup for all plateforms, with a unified configuration, and promote that massively. This will cause another huge political problem: you now have 10000 of tutorials that are referencing one of the old ways, and you will spend the next 20 years explaining to people any previous configuration are not supported. There will be a lot of complains from devs, and pressures from companies.

Either way, you end up with a load of work, and unhappy people, which nobody wants to sign for. It would be better on the long run, but nobody wants to sacrifice themself to be hated in the end.

And that's just one single point.

You still have to solve homebrew troubles, linux distro splitting python and limiting versions, bootstrapping tooling outside of venv, solving the uncanny valley of venv, and so on.

Note that we haven't even touched packaging yet.

”There are only two kinds of languages: the ones people complain about and the ones nobody uses.” - Bjarne Stroustrup
Pretty much this. Any language worth using will have its complainers. This is generally a good thing :)
i feel golang and c partially, take(go sound weird in this context) a different router and we need to appreciate this type of low change languages or the python 3/2 way of change for scratch both are ways to make better software, knowing that allow ecosystems need to be re written i wish in 5 year the idea of python 4 image even when they say don't, to make a new and better langues, lua is the clear example than people want simplicity we need to accept this change or we are hanged by the limitation of our past
There are definitely languages that people complain about but which nobody uses. Hare was a good example of this most recently.
HAHAHAHHA, Stroustrup, author of quite the monstrosity, would say that wouldn't he? rofl
I agree with this so much. I loved Python for decades. Kinda loathe it now. All scripting languages have fallen into this, managing interpreter, test tools, and dependencies in a dev environment, CI/CD, and prod is more work than doing new stuff.

Java/Spring is obnoxious. Spring just enjoys breaking APIs or behavior on patch releases so much. Well, and I have a personal dislike of Java/C++/C# style OO. The temptation to over engineer is too great.

I’ve been enjoying Go more (I have Pascal and C roots). But I feel the pain coming as the ecosystem grows.

I haven’t LISPed in years. Maybe I’ll tinker in Clojure again. I don’t care for Emacs, and last time I checked, setting up a CL was a PITA. Sigh, even choosing a LISP/Scheme is a journey in itself.

Clojure has massive amounts of ecosystem and toolchain pain, even though it is a cool language. Most common dev environment for it is a complex emacs tool chain. If you are seeking the simple joys of programming, Clojure is unlikely to be what you want.
This was the path i was sign posted to take and I felt like onboarding was fun:

    1. I needed to install clojure https://clojure.org/guides/install_clojure
    2. I needed an editor, i wanted to use VSCode so the Calva plugin was what i needed https://calva.io/paredit/ 
    3. I needed to learn how to edit Clojure, i tried going beyond this point without learning paredit and it slowed me down so i came back and invested an evening - in vs code do ctrl+shift+p then choose the calva getting started repl
    4. You need build tooling and it seemed the choices were lein (easy user experience but not “blessed” future direction? - not sure about what i’m saying here  but it’s the understanding i formed). Tools.deps is the blessed approach but designed to customise the heck out of it - problematic for a beginner like me! Thankfully you can park the customisation for later and just get started with a well laid out starter https://github.com/practicalli/clojure-deps-edn - there’s even a video walks you through its features, all the inspectors and visualisers are nice to know about but not needed yet on a beginner journey
At this point I was free to do whatever. In my case so far that’s meant a toy project in reframe (loved it), another in luminus (also loved it), then i went off on learning more of the language since i felt lack of familiarity was most of my challenges with my luminus project.

Clojure is one of my fun languages. I laughed along to a TSoding video where the chap was quite openly dismissive of clojure as he went along but everything he tried just worked and fell into place like dominos. It just made me chuckle. https://m.youtube.com/watch?v=7fylNa2wZaU

I have Bob Nystrom’s interpreters book and i intend to use clojure as i go through that. We’ll see how successful i am…

Clojure with VSCode (with the Calva extension) is a breeze.
Thanks for preventing the frustration there. I’ll try to survey the landscape I guess.

I also haven’t taken on rust. But I’m really wanting to play with a smaller language that has enough to do something practical with. The C replacement languages like Nim are cool, but not appealing for me yet.

It’s been a while since I’ve used a LISP. I’ve always gotten things out of those forays that changed the way I looked at making software.

> Clojure has massive amounts of ecosystem and toolchain pain

Oh come on. Why do programmers like to exaggerate things in plain English? Maybe because naming variables using words like "massive", "colossal", or "monumental" won't fly in a programming language?

There's no "massive amount of toolchain pain". Did you use Clojure last time in 2012 or something?

You can literally just install Clojure and start writing Clojure programs in your shell.

Well, if you want something personalized or project-specific, then of course you'd have to learn some stuff, that's not gonna change for any general-purpose programming language. And I don't know how you can get more general purpose than Clojure - it can run on JVM; on JavaScript platform; on .NET CLR; in Flutter; can do R and Python interop, you can write bash scripts using Babashka and nbb.

The days when you needed to learn Emacs to use Clojure are well in the past. Today you can write Clojure in Vim, VSCode, IntelliJ, Atom, Sublime, Nightcode, Emacs and even Eclipse.

There's been a fair amount of churn in the ecosystem, even if the language itself has been very stable. Leiningen was ubiquitous 5-6 years ago, but if you switched to using deps for dependency management you lost the ability to run tests or build uberjars and had to manually re-create these on a per-project basis. Now there's tools.build, but that also requires you to manually write essentially the same tasks for basic functionality in each project. Leiningen and tools.deps also seem to resolve depedencies differently, so you can run into issues simply by migrating from one to the other.
That's not "massive amounts of toolchain pain", this happens in every general-purpose language, I'd say: that's "business as usual".

Like in Javascript, for example, any lib composed with CRA (Create React App) is painfully difficult to re-use in non-CRA apps. You constantly run into dependency resolution pain with Haskell; Python has toolchain resolution problems; .Net has its own challenges. Well, at least .Net folks don't have to run three different, incompatible versions of Visual Studio anymore to compile a single project. I do remember those days.

If I had to run multiple versions of Clojure, Leiningen, or CIDER on a single machine to compile different projects, or if Clojure folks had to invent something like pyenv, yeah, I'd agree that there is a problem.

You just can't make everyone happy. People either complain that "Clojure is dying" because some lib hasn't been updated since March, or "Clojure has too much churn" because Cognitect rolled out a new lib.

Clojure earned the fame of being very stable because you can pick any five-six years old project and it still would compile. Now you're complaining that you've decided to switch to a different build tool and saying it's painful?

Do you know what's painful? Having to migrate from Angular to React and to keep them both in the same .js project during the transition phase. Clojure has nothing of that sort. So many times we slowly moved from one thing to another with virtually zero downtime.

I can compare the frustration you seem to describe with my own experience building thing in different languages. Clojure by far is the least frustrating in that regard.

(comment deleted)
Meanwhile I just get shit done with PHP and JavaScript. I guess I never have to do anything on the frontend. That’s where all the disasters are.
IMO the problem isn't new features, but that obsolete things are never removed from the language.

But even though a feature is removed from a next version of the language, old code still needs to work. A project must be able to contain vOld and vNext files.

Another thing I also miss is better interop between languages. Is C based interop really the best we can do?

I'm in a similar-ish boat. I enjoy most languages that I learn... for a while. Once the excitement wears off, though, I start to see the flaws or inconsistencies. And, eventually, the flaws are the only things I notice anymore.

Of course, that's as much a criticism of my own attitude as it is of any particular programming language. But, in my defense, I think that we truly haven't "solved" the problem of software development. Ideally we'd need languages that make it easy to describe our human intent, make it hard to make mistakes, and are resource-efficient. There is no such language yet.

I used to also love C++ and Java. I liked the feeling of control that C++ gave me- believe it or not, I thought that writing 5 constructors for a class/struct was somehow good...

It would be hard for me to even say I have a "favorite" language today. The language I hate the least is probably Rust, but even that has its warts, weaknesses, and inconsistencies. I used to like Swift almost as much until they kept tacking on features that are nothing at all like the core of the language- now I kind of hate Swift. I enjoy Kotlin for about 30 minutes at a time until I bump into one of its many design inconsistencies or incompatible/incomplete features. I did enjoy Clojure even though I'm not a huge fan of non-static typing. It at least has a consistent vision and is clearly implemented with real engineering (like using persistent data structures and immutable-first designs, as opposed to most other languages that just tack on random pieces of "FP" and say "Who cares if you make umpteen short-lived, heap-allocated, copies of that array? Computers are fast!" Ugh...).

Javascript and C++ are usually pretty backwards compatible - at the very least, you can run your C++ compiler in compatibility mode for a certain standard, so I don't see any need to get caught up in the churn there.

Personally I've been using Ruby for almost 9 years and I still find it fun. Maybe that's just because I tend to agree with all of the new features they add to it.

I've really enjoyed Golang for this reason. The powers that be take a cautious approach before adding major new stuff, even when the community complains loudly about lack of important features (e.g. generics for many years until recently). Go code I've written years ago is easy to adapt to new versions and ways of doing things, even when I have to switch gears to others languages for months/years at a time. Go is predictable.
> But there was a time when I found Python and Js to be very fun languages. But the ecosystem has been becoming a mess. Build breakages on dependency upgrades are the biggest fun-killer IMHO.

It's not the way I remember. At the beginning you got Python with the batteries - and it was awesome - but for everything else you were on your own, and sometimes it was nightmarish. There was no pip, not even setuptools. Today I can install anything I want with one command on any of the 3 major platforms. Granted, there are glitches and we're accustomed to rapid progress now, but it's easy to forget how far we got.

The irony here is that the dependency hell within pure Scala libraries has improved tremendously and is not really a problem anymore, yet we need to deal with many binary compatibility issues due to transitive Java dependencies.

Things that regularly cause issues, for instance when assembling JARs that get shipped to a Spark cluster at work: Guava, Jackson, Kryo, Log4j, Hadoop's transitive dependencies (like Netty) ... not Scala's fault.

The big takeaway here for me is that Akka has changed license to BSL.

It's almost crazy to me that such a fundamental and widely used project would switch to such a restrictive license.

Some more details here: https://coralogix.com/blog/akka-license-change/

> Lightbend are operating on a “per core” model, with their base license starting at $1995 per core (defined as a thread or vCPU)

> The license is only enforced if your company earns over $25 million in annual revenue

I guess Lightbend is really struggling, but this is probably the end of Akka outside of niche markets / large enterprises.

edit: HN discussion - https://news.ycombinator.com/item?id=32746807

2.6.19 will be forked and a community-driven Akka will emerge eventually.
Has a champion risen to the task yet?

Forking a project is no easy feat. Certainly not one the size of Akka. You need a corporate backer who is going to put at least one person full time on it. I've seen plenty of forks start out with the best of intentions only to slowly fade in to nothing.

It's only been a week since the announcement, I'd expect it'll take a while.
https://www.theregister.com/2022/09/08/open_source_biz_sick_...

Here's an article on it. Their logic actually makes sense. Not that I support gouging customers, but when you consider how there are massive billion dollar companies with expensive lawyers figuring out how to end-around OSS (via SaaS, etc) this is the logical conclusion. A lot of companies make a lot of money on OSS and give little to nothing in return. This isn't in the spirit of OSS but company men don't really care. So it seems like Akka finally got sick of it and is now coming to collect its (without question) overdue paycheck from these people. It's just unfortunate they went so aggressive with it. $2000/vCPU/year will do a lot of damage to smaller projects in the process of sinking the billion dollar open source leeches in the process.

If you’re making $25mil in revenue why is it out of the question to pay for licenses?
Why would you? License requisition is a real pain, they have to be factored into the budget, depreciated, etc. If you can instead simply pull in OSS and hide it behind a SaaS implementation (thereby complying with licenses) you can leverage it to make money. I don't think Stallman saw this coming.

Some companies do better than others. For example, FAANG level companies typically have teams that do give back. In some cases several orders of magnitude more than they take from popular projects. It's the in-betweens, the other companies that don't do anything other than leech.

> pull in OSS and hide it behind a SaaS implementation (thereby complying with licenses)

sorry, but you can do that shit anymore:

https://wikipedia.org/wiki/Open_Software_License#Network_dep...

My interpretation of that clause is it applies to distributing code over a network. The most common example of this is serving javascript to a web browser. I'm pretty sure putting an API in front of a server that happens to run open source software doesn't count as "distribution", which is what we're talking about here with SAAS providers and Akka. If it does, then every site that is backed by servers running linux and not distributing their GPL license to clients is also in violation.
I would disagree with your assessment. OSL was specifically crafted, to close this exact loophole:

> Most other open source licenses treat such network uses of software as internal to the company that runs the server, and they don't require disclosure of source code. That is seen by many nowadays as a loophole that permits large online companies to avoid their reciprocal source code obligations.

http://rosenlaw.com/OSL3.0-explained.htm#_Toc187293088

Sorry, I didn't read your link carefully enough. I stand corrected, that does indeed seem to be the only reasonable interpretation. That said, this clause only exists in this particular OSL license, so it only applies to software distributed under it. Some quick googling indicates that OSL is 20 years old, and OSL v3 (the latest version), is 17. Despite that, it doesn't appear to have any significant usage. PyPi, for example, lists 10 software packages distributed under it [1], out of 387,658 total. So it certainly doesn't seem like a practical solution to the problem.

I suspect the reason that nobody uses it is due to its toxicity - it taints anything that transitively uses it in any practical way. This leads to all sorts of nonsensical violations. For example, say you write a document in a word processor that uses a leftpad lib distributed under this license. Then you email that document to someone else. Congratulations, you're now in violation of the license - you distributed a "derivative work" of the leftpad lib to someone "other than you" over a "network".

The terms of this license are so restrictive and cumbersome as to make it basically useless. Anything you publish under it can't effectively be used by the vast majority of the people who would want to use it, at which point you might as well not publish your work at all. I certainly wouldn't view this as a panacea for solving the SaaS-wrapping-OS-code problem.

[1] https://pypi.org/search/?c=License+%3A%3A+OSI+Approved+%3A%3...

> That said, this clause only exists in this particular OSL license, so it only applies to software distributed under it.

Nope:

https://choosealicense.com/licenses/agpl-3.0

https://choosealicense.com/licenses/cecill-2.1

https://choosealicense.com/licenses/eupl-1.2

> Some quick googling indicates that OSL is 20 years old, and OSL v3 (the latest version), is 17

what does that have to do with anything? A license can be old, its still valid.

> The terms of this license are so restrictive and cumbersome as to make it basically useless

I see this often. This is business speak for "we don't like the terms of some license, so that license is useless for everyone". For anyone willing to respect the license terms, they can have full access to the software.

> If you’re making $25mil in revenue why is it out of the question to pay for licenses?

Turn it around: the kind of company that makes $25mil in revenue does so in part by figuring out what expenses it can negate or avoid. If they don't have to pay for licenses, they won't.

Completely hypothetical anecdote certainly not based on personal experience working in the Bay: an Ops director who saved 50% on MSFT server license costs by only paying for the servers in the DC acting as current primary. "They are not taking production traffic so they are not in use, ergo no need to pay."

As an engineer this logic may disgust you but it's the kind of thing that gets you promoted and 'in good' with "the business."

PS. It's a similar principal to your filthy rich relatives who are surly misers and share nothing with everyone. (And they have no sense of humor, too!)

> the kind of company that makes $25mil in revenue does so in part by figuring out what expenses it can negate or avoid.

Cutting expenses has no direct impact on revenue.

For many companies, it is better to have small recurring expenses than to take on certain types of risk.

The cost for the license would be more than the cost for the hardware to run it tho. We're talking literally doubling, maybe more, of the costs.
Coz you want to make $25 mil in revenue instead of $20 mil in revenue.

The cost is so high actually forking and developing the fork is probably cheaper. Especially for a big company.

Imagine app costing you 100k in hardware, 1 mil yearly in engineering cost but 5 mil in licensing cost just because you have big nice cluster with a bunch of modern high core count CPUs

Because $25mil in revenue might still mean less profit than the cost of Akka licenses will add.

Remember, Revenue is before applying costs - costs like extra million here or there from licensing and costs of servicing the license which I think many people forget about. Especially when the software doesn't have some automated methods of license management.

They kind of went down the communist route, but backwards? From public property to "tax the rich"
Could you add a link (or explanation in parentheses) that BSL means Business Source License and not Boost Software License? I was confused for a few about why people would be up in arms about the boost license which seems to me like an MIT variant.
Am I the only one that doesn't think this is really all that bad? I'll admit that I've not ever written a line of Scala, but in principal it seems like the only people who have to follow this license will be those who can afford it.

Sure, true FOSS is always better, bit the maintainers have to eat somehow. If you're making 25m+ ARR and are using their software, maybe you should be paying them something.

The problem is that there's nothing stopping them from removing that 25m limit and jacking up the price tomorrow. It's putting your company at the mercy of another company which is not an ideal position.

It's also sort of a meta problem. You generally want to use well known libraries/frameworks so that you can hire people with experience. If other companies stop using it because of the above you probably want to stop as well even if you are not worried about hte license.

I think it presents a problem beyond paying.

At my job, I can't just reach for Akka. I need to talk to someone who has the authority to purchase a $2,000/year/core license. If I'm deploying something to 6 instances with 4 cores each, that's $48,000/year for a pretty small deployable. It might be totally worth the price, but I'm definitely going to need to justify to someone that we're going to spend a fifth the price of an engineer because I want to use Akka for this small thing. People will propose alternatives. Before, if Akka was an average addition to the project, it was fine. Most things are average. Now, it's an average addition when we should have used something else and it's costing is $48,000/year.

What happens when we want to scale it up to 24 instances for a week to handle unexpected load? Do we pay $192,000? I'm not trying to sound difficult. I just know the types of questions that will come up in meetings. Likewise, how are we going to account for our Akka usage? Do engineers put it in a spreadsheet that they all forget exist? Won't they just forget when they add a new deployable or when they scale something up? How do we alert accounting or whomever that they need to pay additional license fees when we deploy something new or scale up?

I don't need the same meetings around FOSS. I don't need to involve accounting with FOSS. I don't need to figure out how we're going to sort out the billing. Yes, all these instances will have charges from AWS or whatever, but those are already handled. Yes, companies sometimes buy licenses from JetBrains for their IDEs, but you don't have to worry about those license fees once the code is written - it's a production cost, not a running cost. Yes, after several years Akka goes back to open source (so it isn't a liability forever), but if you keep updating it (including security updates) then it keeps being that liability you need to pay for.

Then there's the issue of ecosystem and vitality. The $2,000/core price is going to shrink the ecosystem down to a tiny fraction of what it used to be. I can hear the comments in the meeting now: why would we be paying $2,000/year/core to buy into a dying ecosystem?

I think the per-core license scheme makes sense to the maintainers - the more you use it, the more value and revenue you're generating with it, the more you should pay us. However, this creates two problems: 1) it makes it hard to deploy low-margin services using Akka so you can only use it in high-margin situations; 2) it means that you really don't know what it's going to cost if you scale up - how many cores are you going to be using a year or two from now?

Microsoft licenses Visual Studio to companies earning over $1M/year, but they're licensing it on a per-engineer basis rather than per-core. Telling a company, "that engineer you're paying $100,000-500,000/year is going to cost you an additional $500-1,000/year," is a very understandable cost and seems like a small/marginal cost per engineer. Telling a company, "that engineer that chose to use Akka is going to cost you an additional $2,000-3,000,000/year," isn't the same thing at all. 100 instances with 16 cores each is $3.2M. You can argue that the company is using Akka so much so they should be paying that much, but at the same time it means that maybe the company would have been better hiring a different engineer that would have used anything other than Akka. If the company had gone with Go or C#, they wouldn't be spending that $3.2M. The company would be better off if they hired a different engineer who wrote the system in Go rather than someone who decided they liked Scala and Akka.

Yes, I'd say it is that bad. The ecosystem will shrivel as people turn away from Akka, it will be difficult to get it approved as you'll need to go through meetings and come up with ways of accounting and paying for...

> You can argue that the company is using Akka so much so they should be paying that much, but at the same time it means that maybe the company would have been better hiring a different engineer that would have used anything other than Akka. If the company had gone with Go or C#, they wouldn't be spending that $3.2M. The company would be better off if they hired a different engineer who wrote the system in Go rather than someone who decided they liked Scala and Akka.

Or even fork it, continue development and just hire few more engineers. There is no amount of consulting that you can provide for a library that would be worth the money

or akka on java.
Thanks for explaining that, makes more sense what the fuss is all about.
i am rewritting all of our projects (about 20 or so) to get off akka as we speak. Pain in the arse, but has to be done. It's a shame. Was fun while it lasted.
Imo this kind of license is a huge PITA with containerized workloads that autoscale, etc. Would one pay based on average core usage or peak usage?
As much as people like to rant about license managers used in proprietary software (and hardware from IBM...), that's a necessary feature for handling that kind of license well.
Well, unless some big player forks it and puts the developers on keeping the development of the fork.
far less likely being scala
Surely it's the death of Akka inside large enterprises (outside of very niche, already written, applications). How can they justify the enormous departmental cost? If a small team in a large company is creating a new product why on earth would they choose to use Akka?

If you're a small company, likely to never hit $25m ARR, this won't affect you... Or is a ticking time bomb should you ever cross that threshold.

The commercial entity behind the Scala language didn't do enough to make it more usable for Android developers. It has been downhill ever since.
I really wonder why every time Scala is discussed on HN, someone wants to rewrite history about some mythical synergy with the Android ecosystem. This is so bizarre.

In what world would Typesafe/Lightbend have found the money and resources to pull off even a fraction of what Jetbrains did with Kotlin? Let alone convince Google.

On the other hand I'm very happy Scala isn't tied to the Android runtime.

> In what world would Typesafe/Lightbend have found the money and resources to pull off even a fraction of what Jetbrains did with Kotlin? Let alone convince Google.

What did Jetbrains do with Kotlin that required money and resources outside of Scala's community reach? (Also, what do you mean about convincing Google?)

I learned Scala a few years back and am working with Kotlin this year. I use Android Studio - I expected to be mind-blown with the IDE support. I wasn't. The only feature worth mentioning is the automatic conversion of pasted Java code to Kotlin, which is really trivial to implement if you have tools for working with AST of both languages and a bit of free time. Scala is handicapped here, last I checked, and only got better with version 3 rewrite, but if that's a killer feature for Kotlin, then replicating it for Scala by heaping regexes until they cover 95% of cases would also work.

I honestly don't see anything in Kotlin and the IDE that couldn't be implemented for Scala as a plugin, if there was interest in that.

I think you're vastly underestimating the amount of work required to support a platform like Android. How many people are directly employed by either JetBrains or Google to work on the Android + Kotlin story, vs the total number of Typesafe/Lightbend employees at its peak... which has always been burning through VC money and is financially struggling even after focusing on their core knowledge domain.

> (Also, what do you mean about convincing Google?)

Google decides what Android becomes or not. What makes you think they would have been interested in Scala in the first place? Even if someone did the integration work for free (which is an insane premise), Google likes boring languages. Plus, Scala's standard library is somewhat at odds with a fast and lean mobile runtime.

> I think you're vastly underestimating the amount of work required to support a platform like Android.

That might be so, but you're not giving me a chance to change my view. I don't know, and don't care honestly, how many people are working on what; I'm asking what did those people do, specifically, that required such an immense amount of work, and what they have to show for that effort. And of course, how many people work on developing Android itself is irrelevant - we're only talking about supporting existing compiler that targets existing implementation of a JVM in an IDE and ecosystem. Put another way: what's so impressive about Kotlin's support for Android?

> total number of Typesafe/Lightbend employees at its peak... which has always been burning through VC money and is financially struggling even after focusing on their core knowledge domain.

Maybe, then, focusing on their core knowledge domain, working for almost a decade on the "next version" of the language without care, then pulling Python-like 2/3 drama when it finally landed, was simply... a bad business decision? Maybe focusing effort on making the language more accessible to more people would have played out differently? (Just guessing.)

> Plus, Scala's standard library is somewhat at odds with a fast and lean mobile runtime.

Why? Generics and implicits are compile-time features - what's in the Scala's stdlib that is incompatible with Android APIs? What does Scala have in the stdlib that Kotlin doesn't?

I'm not going to try to explain why developing and maintaining tooling takes resources.

However, a few things:

- Lightbend isn't involved in Scala 3.

- Martin Odersky has taught students for decades and knows how to make Scala more accessible. He wasn't afraid of stirring controversy with new keywords and the brace-free syntax. He also has enough industry experience and connections to realize what matters for the ecosystem in the long run. Server middleware and big data frameworks are the perfect fit for Scala on the JVM. There's no evidence for some kind of missed opportunity between Android and Scala.

- Scala's standard library is rich, heavy, focused on immutability, and not always interoperable with Java's. Kotlin's standard library is very small and heavily inlined in comparison. On a mobile platform, this matters.

> why developing and maintaining tooling takes resources.

Developing and maintaining anything takes resources, tooling is not special at all. Yet, you still didn't say what exactly does Kotlin do that's so resource-intensive that it's impossible to replicate for Scala for the reason of lack of resources only. Do you know Kotlin's tooling?

> Lightbend isn't involved in Scala 3.

I don't get what you mean? I mean, so what? I just opened scala-lang.org - which seems to be an official Scala web page - and the information that Scala 3.2.0 was just released is at the very top of the page. It's not like PERL and Raku. And what does it matter who is involved in what if we're talking about the tooling for the language as a whole?

> Martin Odersky has taught students for decades and knows how to make Scala more accessible.

Apparently not via investing in tooling, though? If you ask Matthias Felleisen[1], who happens to also have been teaching students for 40 years at this point, he'd tell you that tooling is important for accessibility[2].

> He wasn't afraid of stirring controversy with new keywords and the brace-free syntax.

I don't know who would, actually. I'm sorry, I don't understand this sentence, could you please explain what you mean by this?

> There's no evidence for some kind of missed opportunity between Android and Scala.

I'm sorry, but that's just you being in denial. I don't intend to dispute Martin Odersky's credentials, that's completely beside the point. The point is this: in June 2019 Scala was 28th and Kotlin was 43rd on the TIOBE Index. Now, Scala is still ahead: 33rd place vs. 34th for Kotlin. And you have to account for the fact that Kotlin is almost 7 years younger. Sorry to break it you, but that's not how a healthy language's growth looks like. Clearly, there's something wrong somewhere. My interpretation is that Scala missed many chances, and disastrously so - one of them being Android development.

It's a bummer, really. I read Odersky's book in 2005, I still have the PDF. I really liked the concept of a scalable language, expressive at all levels of complexity. I learned Scala in 2009, then brushed it off in 2017. I see Kotlin for what it is: a pragmatic knock-off of Scala and Groovy. Groovy did not, but Scala had a chance to win over millions of Android developers (in addition to thousands in data centers), but blew it. I'm not happy with that.

(The other great language that could have done better but largely blew it is of course Clojure (currently 47th), but then again, they had it way harder given the language's features)

> Scala's standard library is

> rich,

I don't have a quick way of checking, could you maybe check how many classes/(other relevant entities) are there in Java and Scala respective standard libraries? I strongly suspect Java's bigger. And even that is nothing in front of Python or VW Smalltalk.

> heavy,

Why is it heavy and in what way? Too much code generated? Too big a JAR to include?

> focused on immutability,

All default (ie. used most often in idiomatic code) collections in Kotlin are immutable; the practice of favoring val over var is identical in both languages.

> not always interoperable with Java's.

What do you mean? These are all classes compiled to the same bytecode, how could they ever not be interoperable? Do you mean that you need to convert (for example) collections before you can call methods provided by Scala/Java-specific class? That's perfectly normal and counts as interoperability, and quite a high-class one at that (I mean, try to convert BEAM's list into Python's via C extension and you'll see what "not always interoperable" means...)

> Kotlin's standard library is very small

Again, can't check it easily, but yes, I get the impression that Kotlin's stdlib is a bit ...

> I'm sorry, but that's just you being in denial

Have fun rewriting history then. Google picked Gradle, JetBrains, Kotlin, that's just the way it is. If they had been interested in Scala on Android in any way, they'd put a couple of people behind it when it came out, or at least encouraged some 20% projects. That never happened.

And it's perfectly fine. Nobody cares about the TIOBE index. Scala faces plenty enough of challenges within its core ecosystem, nobody would gain anything from targeting the Android runtime and SDK on top of that. Exactly the same way Spring developers don't give a damn about Android.

> Apparently not via investing in tooling, though?

That's a pretty ignorant comment given the amount of work that was delivered since the creation of the Scala Center.

> What do you mean?

There's a big difference between having to convert all the common data structures between Scala and Java, or simply reusing them, like Kotlin does. Plus, Scala's idiomatic usage of Option is fundamentally incompatible with libraries taking and returning nulls everywhere. Google made Kotlin first-class without having to break the entire SDK. That's a pretty huge reason Scala never stood a chance.

Well, thanks for not telling me anything until the very end. I asked honest, technical questions, didn't expect not to get a single concrete answer over this many posts. Have you been a Lisp or Haskell programmer before switching to Scala? You sound like their spiritual heir...

(EDIT: Also, the ignorant comment was uncalled for. I gave you the exact dates when I was involved with Scala. I don't have the duty to stay updated on what happened afterward.)

> All default (ie. used most often in idiomatic code) collections in Kotlin are immutable

That's not true. List, for example, is a read-only interface, but given that MutableList is a subtype of List, you have no actual guarantee that some other piece of code isn't modifying a list you think is immutable.

I haven't seen this leading to trouble so far because clearly the intent is to treat collections as immutable wherever possible, and because it's a tradeoff that makes Java interop easier, but it's not the same thing as true immutable collections in Scala.

Also, your comment about interoperability makes me think you haven't actually used Kotlin. Its Java interoperability is way better than Scala's (you don't have to cast collection types, for example), for better or worse (because it also inherits some of Java's flaws).

I think that Kotlin is more pragmatic and Scala is more elegant and idealistic, and both are valid goals.

I think it's more of me not remembering how it was with Scala - it's been some 5 years since I did any Scala development.

> I think that Kotlin is more pragmatic and Scala is more elegant and idealistic, and both are valid goals.

Yes, I have the same impression.

However, I don't believe this was an initial goal of Scala. I remember reading the Scala book by Odersky in 2005 (or around that time) and my impression was that Scala was meant to be pragmatic as well. The OO+FP mix was innovative at the time (it's not anymore), but neither side was made to be dominant. That changed, with - and I'm guessing again - Haskell expats who abused implicits and the type system almost to the point of breaking to pursue their brand of "generic programming". I don't know what happened exactly and why, but when I learned Scala in 2009 it was because I didn't want to touch Java but I had to work on the JVM with lots of Java libraries. And Scala back then was ok for that purpose, like Kotlin is today. When I revisited it in 2017, it was still kind of ok for that and for me, but the community and ecosystem seemed to have drifted away from the "better Java" use case significantly.

On the other hand, Scala 2 is now anything but elegant. Scala 3 made Scala elegant again. You can see how many changes were needed to recover from more than a decade of giving in to people interested in a particular style of programming by simply skimming the Scala 3 tour.

My background is kind of unusual: most programmers my age have worked with 5-6 languages professionally and a few more as a hobby. I used 9 languages professionally and more than 20 as a hobby. Scala was one of the most interesting languages I learned. It was C++ done right and without the design-by-comitee stigma. It was meant to be expressive at all levels of complexity, from oneliners to massive systems: Scala, a scalable language. My impression is that the initial goal was to use FP idioms to make the language expressive "in the small", and OOP to make it expressive "in the large". Then some part of the community started wielding FP hammer and striking every problem with it, without even trying to use the other part of the toolbox.

I might be wrong in all of the above, I'm just guessing based on hazy memories of long ago. Still, that's my impression as someone who is interested in programming langauges in general and who was around since the beginning, although only reading up with Scala development occasionally.

Another language that suffers similar fate is OCaml. Actually, object oriented part of OCaml is a beautiful and elegant, prototype-based and (statically) structurally-typed object system. Yet no one seems to be using it. However, OCaml is better at FP than Scala. The H-M type system and inference along with polymorphic variants cover a lot more than Scala's FP can (without abusing the language features; and also of course H-M comes with downside, ie. + and +. thing). OCaml also provides real modules and higher-order modules (dubbed functors) which Scala doesn't have, and which also improve FP style to cover more of the programming "in the large" more easily.

Again, I might be totally wrong, but I think Scala was never meant to be "Haskell on the JVM". Scala 3 highlight the pragmatic, elegant side of Scala, which I think makes my assumption plausible. (I also like Haskell, Lisps, Erlang, Prolog, and another 20 languages, so I personally could live with that direction of Scala's development. Other than the compile times. But there's no way to argue that it resulted in higher adoption rate, larger community, more packages in the ecosystem, and so on. So while I'm personally still ok with Scala, my employer is not. And comments like that of your sibling poster don't help, to put it mildly - it's Smug Lisp Weenies again, just with ( replaced with { ...)

(BTW, if I'm wrong, please tell me. I'm capable of changing my mind...

> Maybe this is just me getting older (going to turn 40 soon). Maybe all programming is terrible.

Similar age and that is my experience. There are just so many roadblocks, things that don't work properly and you need to mess around debugging or googling github/stackoverflow to resolve before you can get to the fun part. I'm sure this was the same when I was younger, but I had more energy and was able to plow forward regardless.

I love Scala, now I love Rust
They are both awesome. Good reasons to love them both even though they both have their problems. :)
I think one more problem with Scala, apart from the lack of stability and having to solve the language's problems instead of your application ones, is one of local maxima.

Most of the ecosystem uses monads. And the way most projects end up using monads is have "the one monad" that every function returns. ZIO is an example of that. Understandable, since the alternative is to have tons of different function colors.

However, since in that case the monad really is just a configurable semicolon semantic, you've just gone full circle and chosen a single global one.

And in that case, why not just choose a language where that semantic already is the core semicolon semantic of the language? You're living with a ton of complexity for very limited gain.

1. Because different projects will want different monads

2. In my experience, having up-conversions between different monads is intuitive low-noise

> Because different projects will want different monads

It doesn't look like that to me, based on how the ecosystem currently converges on a single one. I understand there may be some projects that do that, but if the majority converge, then it's still needles complexity.

However, I might be wrong. I've been an external observer for a while already.

History proofs this wrong. Just look at it: first there were Scala Futures and Twitter Futures. Then there came Scalaz and Monix, later Cats-effect. Now ZIO also joined. And each library even brings different kind of effect types.

And all of that works, even in combination! This is as if you mix angular and react. Sure, you should try to not do that as much as possible, but the mere fact that you can do this in Scala is a sign of awesome language and library design that is far outstanding compared it the majority of other languages.

You could never come up with the "one true solution" from the very beginning.

> You could never come up with the "one true solution" from the very beginning.

I think I can! I mean, that's what science is for, right?

I'm not so sure. The problem is that the world is moving, including hardware, software, interfaces but also people and process. Languages have to optimize against a moving target. So naturally it's a good idea to optimize for something moving and not something static.

This is what makes Scala good. The language itself is not very complex actually, but it enables complex and powerful libraries.

We are still in the phase where concepts are settling. Pretty sure nobody in a 100 years will think that Monads are a good idea.
Monads are like numbers. You can think they are not a good idea, but they are just a matter of fact and existence.

Also, in a 100 years maybe our brains will be completely different. How do you optimize your programming language for that? I don't think you can.

Given that our brains have been the same for a few thousand years, maybe I don't need to optimise for that.

Anyway, what we currently have as programming languages are all workarounds. Necessary for now, because how else would we program? But in the end we need to converge programming, math and logic, and once this is done, we will be ready for anything. And we won't need monads as a crutch, forced upon us by a type system. I am sure the concept of number will outlive the concept of monad in terms of popularity.

Programming languages will converge after(!) natural languages have converged. Not gonna happen in our lifetime!

> I am sure the concept of number will outlive the concept of monad in terms of popularity.

It already does. I don't get your point...

> Programming languages will converge after(!) natural languages have converged.

Interesting point. But I think you emphasise too much the surface syntax of the language. The language will be a new form of mathematics, and it will be universal, with adapters to various natural languages, of course.

That's beyond me. I guess I prefer to look at what can happen during my life-span. :)
Oh, I am working on that universal language right now. Shouldn't take more than 15 more years or so.
> But in the end we need to converge programming, math and logic, and once this is done, we will be ready for anything. And we won't need monads as a crutch, forced upon us by a type system.

1. Math is filled to the brim with monads, it's just that mathematicians are necessarily specialists, and tend to think about things in terms of their applications to their specialties: they talk about closure operators or algebraic theories or formulas in a formal language, rather than monads as such. But that doesn't mean the monad structure isn't there.

2. Convergence between math and programming (which I agree is desirable) will almost certainly see type theory become more prominent, not less. There is some chance that programmers turn to constraint solvers or ML models for program verification instead, but if they do, mathematicians will not follow.

Type theory is already dead, it just doesn't know it yet.
> We are still in the phase where concepts are settling.

Yes of course concepts are still settling, and they always will be.

> Pretty sure nobody in a 100 years will think that Monads are a good idea.

Why? I for one am pretty sure monads will be a useful concept a hundred years from now.

What about functors, will that concept also be obsolete?

Listen, Monads are fine, Functors are fine, use them wherever and whenever you like. The problem I have with them is that they are making things explicit that are intuitively clear (Monads more than Functors). That is useful in some situations, but in most situations it is not, and just uses up precious brain capacity. If you go to the shop, you are not expecting someone at the entrance telling you that you have to pay for what you buy, and before paying, you are not telling the cashier that you are going to pay them now. You just do it.
One example:

Any project using a transactional database will want a monad for actions that occur within a single transaction (see e.g. the Slick `DBIO` monad).

> why not just choose a language where that semantic already is the core semicolon semantic of the language?

The semicolon isn't semantic. A "semicolon" monad is essentially a single global context object. Most languages let anyone anywhere introduce a global context accessible from everywhere else. At least a monad lets you track it all.

It's not just context. It's also asynchronicity and error handling for example.

The semicolon semantic is how operations separated by semicolons (or newlines) are evaluated and how they impact the general state the program is in. Which is also what a monad's flatMap does, in a configurable way.

No, it is just context. Which context you choose in which part of your code is up to you. Somewhere I might choose ZIO. Elsewhere I might just choose an error-context. Or a state-context. Or a "let me accumulate some extra information while doing data-rprcessing"-context.

And it is always explicit when you are in a context and which one it is. This is really the strengths over languages where this concept is missing. Those languages will just merge and mushup contexts and you never know exactly which things are safe to use and not.

I know you can do it, the question is whether it's mainstream to do it, or whether in practice you end up with a single one in 95% of the cases.

Based on using it a bit and talking to many, more or less disillusioned, scala developers, my opinion is: it's not worth it.

It's fine for us to disagree though. There's enough programming languages and projects for everybody.

It is very mainstream to do that.

Show me a project that is not just a small playground that uses either ZIO or cats-effect and does NOT use another context such as Either/Try or Option or List, ...

It seems (to me) less complex to have that as "just a library".

In most of my little projects, I don't use ZIO, I just have a tiny library I wrote years ago that lets me write stuff that works ok whether it's a Future[Seq] or a Seq[Future] or a Future[Seq[Future[Seq]]] underneath. https://github.com/wbillingsley/handy

If ZIO (or some other choice) were baked into the language, I'd be using their choice of async libnrary for everything whether I want to or not.

And I wouldn't be able to switch to the new-shiny-and-exciting-thing that comes out when I want to explore it because "sorry, X was what the designers chose when the language was written, so X it must be".

In Scala, I can use my little thing I'm familiar with, or I can try out ZIO, or Cats-Effect, or Akka Streams (before the licence change). I get to explore concepts very quickly and very easily without having to shift languages and learn a new set of build tools and syntax at the same time.

(comment deleted)
Wasn't this a somewhat common opinion 10+ years ago, when it looked increasingly C++ in its split of user bases (weird operators for one, less boilerplate Java for others)?

I mean, that's how we got languages like Ceylon, Fantom or Kotlin.

I think lots of programmers (including myself) get lost in the programming language features and forget to have fun with what the application actually does.
I'm doing a Play framework upgrade at work right now... and boy did the scala ecosystem not make this easy.
Was it ever? To me it always seemed like a Java with the added burden of functional programming and more complicated OO.
It took some adjustment but I love it now. Not sure I could go back to Java.
Programming isn't fun anymore. Modern ecosystem is too complex for fun.
Are all of them though? Web stuff is if you fall down the hole of "everything must be a docker container" and "chase latest JS fads" but I wonder if there is a saner route. Also things like console apps should still be pretty sane, depending on what you are building.

However trendy programming has very much become pointlessly complex.

(comment deleted)
Regarding Akka situation. I am feeling Java Loom + Structured concurrency[1,2] is coming at write time. I think lot of existing project will try to shove in virtual threads in reactive solution in sub-optimal way and It may not lead to great results. Already an implementation of Loom based server is out[3]. Going by how simple code looks and how performant code is compare to reactive solution even in ALPHA release. I am going to be using it very soon.

1. https://openjdk.org/jeps/425

2. https://openjdk.org/jeps/428

3. https://medium.com/helidon/helidon-n%C3%ADma-helidon-on-virt...

Loom will be the next billion dollar mistake after nulls. Keep my words in mind for a decade or two...
Okay, are you going to give reason or is it more of a Thought leader style pronouncement?
Haha, I guess you are right.

The reason why it is a mistake is because it is essentially trying to solve the rpc problem once again even though it has been tried many times without success.

There just is a difference between making a synchronous call within your own OS thread vs. making such a call against anything else (the filesystem, the network, ...). Because you can assume that a synchronous call either succeeds and you can continue whatever you do. Or the whole thing crashes because e.g. the thread was killed due to some external effect or OOM error. But in that case, you have the guarantee that no more code on your thread is being run.

With Loom, it is not clear anymore if more code will be run based on your call or not, since there isn't an immediate difference between the two types of calls anymore (when looking at the code). This missing distinction is exactly what makes it easier to use but it also makes it very easy to use the "wrong default".

Joe Armstrong (the creator of Erlang) said the same thing back in 2008.

> The fundamental problem with taking a remote operation and wrapping it up so that it looks like a local operation is that the failure modes of local and remote operations are completely different.

> If that's not bad enough, the performance aspects are also completely different. A local operation that takes a few microseconds, when performed through an RPC, can suddenly take milliseconds.

http://armstrongonsoftware.blogspot.com/2008/05/road-we-didn...

Thx, always feels good to be confirmed by what someone write ~15 years ago. I think he's right.
A comment under Joe’s post points out that this has been understood at least since 1994.

> We argue that objects that interact in a distributed system need to be dealt with in ways that are intrinsically different from objects that interact in a single address space. These differences are required because distributed systems require that the programmer be aware of latency, have a different model of memory access, and take into account issues of concurrency and partial failure.

> We look at a number of distributed systems that have attempted to paper over the distinction between local and remote objects, and show that such systems fail to support basic requirements of robustness and reliability.

https://web.archive.org/web/20030310070307/http://research.s...

I think that I disagree. Not because I think Loom is a good design, but because I've seen the same design mistake committed a couple times before, and, despite initial hype, people tend learn to hate and avoid it long, long before it can become as intractable a problem as null is.

The worst I anticipate coming from it is some hassles in production and a whole lot of time wasted futilely trying to explain why I don't like it to people who've had 1/10 as much time as me to become bitter and jaded from working in the profession.

> there isn't an immediate difference between the two types of calls anymore (when looking at the code)

There is: sync calls don't change. Async calls use the Future::fork call, all within your parent thread block scope.

Are you saying that Thread.sleep() will still be blocking its OS-thread completely so that this thread executes no other code until the end of the sleep call?

Because otherwise your claim "sync calls don't change" is wrong - since this is how it currently works.

That's the very definition of what sleep() does, and the reason why, if you're calling it in an async context, you need to dispatch it in a special "blocking" dispatcher, as opposed to the other regular async calls.
That doesn't answer my question to the OP. I know what sleep() does and how to use it, but that's not the point.
We are talking virtual threads here(project loom), i think, no?

https://openjdk.org/jeps/428

Basically, you don't have a thread context anymore, or you don't have a use for it anymore

> We are talking virtual threads here(project loom), i think, no?

No.

Currently, when I have code (not using futures or anything) and in the middle there is a Thread.sleep() then I know that this thread will be blocked until the sleep is over (or interrupted) and _no other code is being executed on this thread_.

So the question is: will this behaviour change? Because if it does, then Loom breaks existing code. And that's what it does. And it does it not by accident but on purpose, to retroactively improve performance of exactly those situations where OS threads are blocked.

ah ok i see your single thread is blocked nevermind
I'll take your bet.

First of all, the difference between threads is not nearly as severe as the difference between (remote) machines. There is an analogy to be made, but that's all it is - an analogy. Most applications don't care about nitty gritty thread-management performance.

Second, people said all that shit about network calls and yet... here we live in the age of distributed computing and it keeps getting more distributed. It's rapidly getting to the point where remote boundaries are something you consider as an optimization step. Most boring old business applications are "fast enough" even though the XyzService lives on another machine.

> First of all, the difference between threads is not nearly as severe as the difference between (remote) machines

The whole reason for Loom is to improve performance of code that would otherwise be blocking. So what code is blocking? Exactly: code that waits for the OS (files, network, etc.). A call from one thread to the other isn't really a blocking call and that is not really what project Loom's main focus is about - at least as far as I can tell.

Doesn't the problem you mention for Loom applies equally to OS threads? What's the difference? Loom just lets you create more threads but with OS threads you are doing IO too.
This is independent of OS threads or green threads. The problem is that with Loom the developer loses control whether they can execute something on one OS thread only or not. Whereas right now they conciously have to decide if they want to run something sync or async.
Nothing is stopping the developer from starting a single thread executor and using that to launch many virtual threads. Is that what you meant?
Well, that is something that is desired and also something we can already do in the JVM world.

What I mean is that semantics of existing code changes (and becomes harder to understand for future code).

Loom doesn't hide exceptions. Now you just write the exception handling the same way you would write synchronous exception handling.
It does look awfully like the async/await mess languages with bad concurrency adopted as a crutch for not having good concurrency.

Erlang/Golang model of superlight "threads" exchanging messages appears to be much better at both being actually concurrent and making most code look decent and easy to see what is actually happening.

> model of superlight "threads" exchanging messages

That's exactly what Loom is.

Goroutines have been very successful.
And not just goroutines. The whole Go runtime is basically what Loom aspires to be. All functions async by default and preemptible. Writing code that looks like it's blocking but is in fact async. "Await" as the default action to do with an async function, and "go" being the optional action.

So far the reception has been very good and it works very well in practice. To me it's a pain now to work with languages that don't work like that. I'd argue it's Go's biggest advantage, really.

The Zig approach looks very good as well (If I understand it correctly, the underlying functions basically get compiled to whatever the caller wants them to be. Async or not. We'll see how that pans out in practice as the language gets more traction.).

"All functions async by default and preemptible." Really? I thought functions were sync by default unless you add the 'go' keyword.
The `go` keyword means you want to run this function concurrently to what you're doing right now.

You can think of it this way, to use terms from other languages: in Go, every function really returns a Future. But every function call has an `await` implicitly. Using the `go` keyword signals that you don't want that `await`. The call-site action doesn't change whether or not the function itself is asynchronous or not (it is).

However, if you use a mutex in Go, or wait on a channel, or try to write to a TCP connection, those calls won't block an OS thread. Additionally, if a goroutine goes on too long and others are waiting, it will be stopped and the OS thread will work on a different goroutine for a while.

Is this really true? My impression was that the 'go' keyword means a green thread is spun up for the function to run in and this wrapper returns immediately (hence the need for channels or waitgroups etc to get the results back). I can't imagine that every synchronous function call creates a green thread, that seems massively wasteful.
It doesn't create a green thread.

I meant async in the technical underlying runtime sense of not blocking an OS thread when doing seemingly blocking operations and tried to describe it in an approachable way. Async in the sense of a python or rust function that is declared as async. If you think in terms of function colors (async and non-async) Go only has async ones.

The `await` and `go` bit are an intuition about how Go works, where waiting for the result right away is the default, while running concurrently needs to be called for.

It of course doesn't create needless goroutines on every function call.

I don't see anything in the docs about cancelling a standard function. Maybe internally Go represents a function as some type of future but for all practical purposes, it looks to me like a function in Go is just as synchronous as as a function in say java.
There's a big difference. If you write to a file using the stdlib in java, you will block an OS thread. In Go you won't.

That does not mean all Go calls are cancelable, they're not.

If, in a Scala/Python/Rust async function you use a synchronous stdlib function, that call will block the whole OS thread with it.

The following experiment will show you the difference:

In Java, run 10 futures on a threadpool of 4 workers, with each future doing a thread.Sleep(1s). That will finish after 3 seconds.

In Go, run 10 goroutines with GOMAXPROCS=4, with each doing time.Sleep(1s). That will finish after 1 second.

Yes I understand the difference between threads and fibers. That is a much different conversation than "All functions async by default and preemptible."
If you run non-async (blocking) code in a fiber, then it will block the underlying OS thread.

Functions need to be compiled in a special way and use IO in a very specific way (async io) in order for them to be properly runnable by fibers.

This specific way is commonly referred to as "async", or "nonblocking", and all functions in Go are that way, including all IO functions available in the stdlib.

It was always an ugly pairing of Java and worst of functional programming imo
> We’re left with the Scala FP communities, which yield awesome libraries and are awesome people, but the ecosystem is essentially a microcosm of the US political landscape.

This sentence puzzles me. Does anybody know what the author could have meant with it? As a European Scala FP programmer, I have no idea.

Typelevel vs ZIO (John DeGoes) drama? Allegations against Jon Pretty?
If you click on the "Politics" tag (which the author has attached to the article...), you'll quickly learn why.

They are a fan of free speech == unrestricted speech. Most larger ecosystems these days have a code of conduct, restricting some forms of expression if they are deemed detrimental to the community. Something that very much riles advocates of unrestricted speech. Often, having a code of conduct is conflated with social justice activism - a movement that is prominently lamented in US politics more so than Europe.

Note: I'm not interested in debating which side is right here, or if that conflating of positions makes sense. Just pointing out the likely origin of the "microcosm" comment.

There's a lot of players involved in the Scala OSS drama. You can read about it here: https://www.reddit.com/r/scala/comments/9a11p1/newbie_wonder...

Suffice to say there's a lot of people at each others' throats, and it probably won't get better.

That thread is 4 years old...I wouldn't say that's reflective of the current situation, nor do I find "probably won't get better" a great take, because the Scala OSS situation tries to not-repeat-mistakes.

Hell the worst thing the Scala Discord deals with it are spambots!

Well, since then various factions that emerged have only come to hate each other more, a prominent "middle ground" member of the community disappeared after accusations that he was a sexual abuser, and the ecosystem seems to have firmly split between Zio and Cats, so I wouldn't exactly say things have gotten better.
> since then various factions that emerged have only come to hate each other more

There are (recent) threads out there on the interwebs were people suggest using Cats Effect or ZIO(or as a better Python) without it being hateful. And there are enough people not going at each other because of some effect library.

I am not saying everything is good, there is enough room for improvement, but I feel like you have an outdated view of the Scala ecosystem. For example "ecosystem firmly split between ZIO and Cats" doesn't ring true either, there are tools/libraries like, scala-cli and Mill or tapir coming out that offer a more pragmatic experience, without locking you down to the pure FP dogmatism.

> a prominent "middle ground" member of the community disappeared after accusations that he was a sexual abuser

Yes, this stirred up a lot of controversy and I found this indeed a failure of the Scala community, I don't think that means things haven't gotten better though.

tl;dr Some of the notable FP people in the Scala ecosystem associate with known white supremacists and support them. [1] When confronted, this small subset of Scala folk decided to side with supporting the white supremacists because they aren't personally negatively affected by racism as they're white themselves. This small group of prominent Scala folk bifurcated the Scala community. They then went on to gaslight others by claiming this is "free speech" (it's not) and causing conflict. The Scala community responded by adding codes of conduct to various conferences and OSS projects, which compel members to act morally.

[1] http://meta.plasm.us/posts/2020/07/25/response-to-john-de-go...

This is a bunch of disingenuous, guilt-by-association, kafka-esque nonsense.

For instance, defending someone against the charge of white supremacy is clearly not the same thing as defending white supremacists.

That neither you nor the article you linked bothered to acknowledge that distinction is quite damning of your ability to think critically.

If you want your engineers to spend time playing with highly academic libraries that are unnecessarily complex for the business problem you are trying to solve, choose Scala.
Highly academic libraries, because of course companies like Comcast or Disney Streaming are universities.
Although there are some complex libraries available for Scala, there's also a lot of very simple stuff.

It's a very expressive language, and sure that lets some libraries do some very powerful and complex things or find new abstractions that'll come across as really complex.

But it's also very good for expressing things simply. Earlier this year, I wrote some materials for teaching git in a little interactive OER I've been trying to build up. With Scala, I could write a little git simulation and embed it into my slides and it did not seem like a big undertaking.

Across these and the decks after it, there's quite a lot from simulating git, to visualising diff a simple diff algorithm, to doing git graphs that'll sit well in an interactive slide https://theintelligentbook.com/supercollaborative/#/decks/vc... https://theintelligentbook.com/supercollaborative/#/decks/vc... https://theintelligentbook.com/supercollaborative/#/decks/vc...

to letting students do an in-browser tutorial that tries to simulate a VS Code-like environment https://theintelligentbook.com/supercollaborative/#/challeng...

In the JS or TypeScript ecosystem, I think I'd have been hanging off so many libraries that I'd be dreading how fast my dependencies move. Here, I've got a dependency on one JS text editing widget and one JS Markdown parser, and one Scala dependency on (my own) little front-end framework ... and that's about it. The rest I could "just write".

Ok, my code ain't fantastically commented because I'm not expecting collaborators, but there's 15 commits in writing the whole darn thing, including the slide decks and interactive tutorial. https://github.com/theIntelligentBook/supercollaborative/com...

Or just have a culture of shipping projects without futzing. We have dozens of Scala services and many dozens of engineers and this hasn’t been a problem.
I worked at a Scala shop, a little over 10 years ago, and it wasn't fun then, either. 1) IDE support was unstable (Eclipse was basically unusable, IntelliJ was better.) 2) Builds were slow 3) Everyone using their own little dialect, and arguments would ensue over whether we should use that feature or not.

Perhaps it's better now.

It is, by quite a bit.

While the "Scala IDE" project is dead for all practical purposes, IntelliJ IDEA's Scala plugin is actually pretty amazing. There's also a VisualStudio plugin that does pretty much the same and is advancing by leaps and bounds. There are also interconnecting projects that provide i.e. language server or build server that are reused by other projects. It's pretty modular. Metals (https://scalameta.org/metals/) is amazing.

In general the language has become a wee bit faster to build, there was good progress with build times during the 2.12/2.13 cycles.

With Scala3 the language got a bit simpler; concepts that were implemented explicitly using (hehe) implicits got their own keywords and a lot of the opinionated boilercode that cause a lot of debates is now generated during complication and hidden. A lot of "standardization" has occurred.

I think the IDE issue still exist in many projects due to the complexity of generic FP libraries + bad support for scala 3. The last scala project I worked on used scala3 + cats and it was very touch and go if we could continue using this stack due how flaky intellij behaved. Multiple times a day autocomplete would just stop working. This btw was noticably better in scala 2.13.
I experience 1 & 2 quite a bit, 3 a bit less but I can totally see how that would be a problem.