Man, I never thought Scala was fun. Always struck me as a functional language that was more complicated than it had to be because it needed to interoperate with the existing Java ecosystem, run on the JVM, handle Java exceptions, etc.
I used to enjoy scala. I believe there’s an element of nerdsniping ourselves when we choose to use scala because it’s fun. That complexity is part of it, and the ability to construct correct programs if you can get it to work is the fun (or was for me).
I had a sort of out-of-body experience reading (skimming) this article, as I realized that it’s been long enough since I was involved in java/scala that I don’t remember any of it, don’t care to, and am happier now for it. I guess I’m lucky I don’t have PTSD over it.
I am very jealous. I’ve been writing Java for far too long and am longing for the day I can jump ship and work with / on more exciting languages. I had been writing Java for 8 years when they finally added local variable type inference.
I recently started to do Scala, semi-seriously, and I am very happy. Especially, since I created a new project from scratch, which allowed me to use Scala 3 with its new Syntax rules. I am always looking forward when I can spend some time coding Scala. For me, Scala is much fun. 🙃
Kotlin is a lot more fun, but I still constantly deal with horrific, soul-sucking dependency management issues. We are using 4 different versions of Guava. Don’t get me started on actually deploying Java to Windows/macOS/Linux users.
The best dependencies are ones that don’t change. I learned yesterday that Guava’s HostAndPort#getHostText was renamed to getHost for effectively 0 reason and, of course, we had code that we want to run with multiple Guava versions calling that method: a choice a dependency made turned into a NoSuchMethodError for me. Gradle is a good enough build tool that I can slap hacks where I need them.
I am very curious to know what dependency management for Elm is like, with their auto-updating-semver for packages. Sounds like it could go really well or really bad depending on how it’s implemented.
There are good reasons to do simple renames of APIs (consistency being the big one). I really liked the way go handled this, with go fix tooling to do the substitution.
In Java, this kind of thing is much harder. If the class or method are not final then subclasses might override them, so renaming is more than a simple text substitution.
Nothing intrinsically, the complexity comes from building modules we want to work with old code that could be using any one of these versions of that dependency. For some of these, we choose one version to build this module against and fix up NoSuchMethodErrors when we see them. Other cases we do more hacky things to ensure field/method access is checked at compile time. You’d effectively have the same issue in any other language + build system.
guava is using semver, but they are using it to an extreme. Basically every release is a new major version, so anything goes. An API that worked in version 21 is gone in 22. There are very little or no guarantees. The thing is that the build tools assume that this is not the case. It is even more fun when you learn that sbt, gradle and maven all have different dependency resolution algorithms/order meaning things that work fine in one tool, breaks in another.
Simply put, having two libraries that depend on different versions of guava is a ticking time bomb and things may break or not. There are no guarantees.
While this is all probably okay w.r.t. semver, this is not what people expect from libraries that are basically used everywhere.
If multiple versions of Guava is a “ticking time bomb” for sbt/gradle/maven, it seems to me (coming from Rust world, where multiple versions are common and well supported) it is sbt/gradle/maven that is broken, not Guava.
well, guava is by far the worst library in the eco-system with this behavior. Sure dep. resolution is problematic in java land, but there is something to be said about a library being backwards compatible and reliable.
It is not good practice to behave in the way the guava devs are behaving. Aloso “fixing” java dep resolution everywhere is a lot harder than avoiding guava.
edit: I want to add that rust had it easier because they could see what works and what does not when they build out their tool chain. In java things have grown organically and there is not one single blessed way of doing things. That makes them hard to compare imho
Not sure what the author means by “the ecosystem is essentially a microcosm of the US political landscape” but it sounds awful. I never got much into Scala. I loved Haskell and liked Java but the hybrid form wasn’t for me. It seemed to me, at the time, that either you were worried about Java integration, or you weren’t, in which case you got to use ScalaZ.
The dependency hell he’s describing, I think happens similarly with Java and Python anyway.
Or, he could literally spend five minutes on Google and get all the context and content he wants instead of defending something he knows nothing about first which makes it look like he’s in support of them. Lobste.rs, like Reddit and others, is social media, and I don’t expect every person to list the entire history and context of everything they reference in their comments.
Here’s some context, John De Goes (JDG) invited a literal fascist to a conference with widespread opposition. Got banned from another ecosystem in Scala. This blew up in 2021 and Martin Odersky (BDFL) voiced support of JDG.
For the record, hereby I also voice support of JDG. Curtis Yarvin wasn’t invited to speak about fascism at LambdaConf 2016, he presented a technically interesting work which was appropriate for LambdaConf. By all accounts, except for boycott of Curtis Yarvin, there was no problematic incidents whatsoever at LambdaConf 2016, including behavior of Curtis Yarvin, who behaved polite. I stand against insanity that is cancellation.
Hobby projects aren’t technically interesting work. Grifts are technically interesting, but we shouldn’t let the original authors of the grift be the ones who explain its technical merits, since they are incentivized to continue the grift.
Curtis Yarvin’s presence is a problematic incident no matter the subject of his talk
Your assertion may be true, but saying it without explaining why it is true is not conducive to conversation, and does not help others to understand. There are no points here to be won; this is no battle to slay one’s enemies. You simply have an opportunity to share – to explain why inviting a fascist to a community event is a bad idea. Don’t miss this opportunity to calmly and thoughtfully explain.
I do understand that some people, reading this, will have no desire to understand your point (just Ctrl-F for the term “cancel”). They will refuse to understand regardless of how carefully and thoughtfully you explain. Your job is not to attack them; if they wish to remain unconvinced, you must allow them to live unconvinced. Let them be.
Your job is to help others who are reading, who are willing to consider your reasoning but do not yet fully understand the topic, why inviting a fascist to speak at a community event is dangerous and/or damaging to the community. Why is it so important, in your mind, that we draw a firm line on this topic? What damage could be done by not drawing that line? Explain, patiently; it is an investment of time, but your written words will outlive us all. And try to honestly acknowledge what the difficulties and costs are of drawing that line.
American politics has been the plague lately. 😢 So it sounds like the Scala community hasn’t been able to dodge that topic, either. There have been a few crazy-big-blow-up community issues lately, including in Haskell a couple years back.
On the technical topic, I’m curious if anyone has encountered any good solutions for “dependency hell”. Let’s assume that you are using a language with a vibrant community, and libraries aren’t massive monoliths (i.e. lots of libraries, composed of lots of other libraries, with a complex dependency graph). Do any language handle this well? Or if not languages, do any library managers handle it well? (Or …?)
It’s something I’ve lived through more than a few times, so I have my own proposed solution to it, but I’m curious how other people attack it.
NPM (javascript) solves this problem by installing transitive dependencies underneath the libraries that depend on them, and preferring to resolve dependencies from a peer level node_modules folder first and walking towards root if a match is not found. So if I depended on left-pad, and also another library that depended on a different (non-semver compatible) version of left-pad, when I install dependencies the directory would look like
I think Rust works fine. Rust allows multiple versions of the same package in the dependency tree. There is no conflict because different versions get different name mangling.
Yeah… I think the alternative of keeping tabs on duplicated dependencies is by far preferable to being blocked on an impossible to resolve dependency conflict.
It’s perhaps too early to tell, but my experience is that the Go ecosystem has done well here. I don’t know if I’ve just happened to be lucky in picking libraries maintained by careful people, or if it’s actually some real difference. But, I’ve had a good experience, compared to other languages I’ve done significant amounts of code in.
Random thoughts that may affect experience
Go encourages duplication over coupling, which perhaps leads to fewer relationships in the dependency graph / larger libraries on average?
Go itself has touted the backwards compat guarantee of the 1.x language, and the community repeats that often
The library dependency scheme they eventually landed at encourages, effectively, renaming a library if you break backwards compat (eg. the v1/v2/vN namespace scheme)
The interface approach? You often see libraries declare SPIs rather than depending directly on external APIs, and then implementing shims, so things end up being less coupled, in a way?
[Comment removed by moderator pushcx: Removing subthread that doesn't improve this hard topic. Why would you think adding religion to a discussion about fascism would _improve_ things?]
Man, I never thought Scala was fun. Always struck me as a functional language that was more complicated than it had to be because it needed to interoperate with the existing Java ecosystem, run on the JVM, handle Java exceptions, etc.
Clojure is a functional language that runs on the JVM that is actually very simple. It makes very different design choices.
Maybe Clojure’s cool. I have nothing against it in principle, I’ve just never used it myself.
I used to enjoy scala. I believe there’s an element of nerdsniping ourselves when we choose to use scala because it’s fun. That complexity is part of it, and the ability to construct correct programs if you can get it to work is the fun (or was for me).
I had a sort of out-of-body experience reading (skimming) this article, as I realized that it’s been long enough since I was involved in java/scala that I don’t remember any of it, don’t care to, and am happier now for it. I guess I’m lucky I don’t have PTSD over it.
I am very jealous. I’ve been writing Java for far too long and am longing for the day I can jump ship and work with / on more exciting languages. I had been writing Java for 8 years when they finally added local variable type inference.
tfw started working on a new project at work, started in 2020, that’s still built for Java 7
I recently started to do Scala, semi-seriously, and I am very happy. Especially, since I created a new project from scratch, which allowed me to use Scala 3 with its new Syntax rules. I am always looking forward when I can spend some time coding Scala. For me, Scala is much fun. 🙃
Kotlin is a lot more fun, but I still constantly deal with horrific, soul-sucking dependency management issues. We are using 4 different versions of Guava. Don’t get me started on actually deploying Java to Windows/macOS/Linux users.
I feel like I never truly understand what I’m doing with Gradle, just copy/pasting until all the IntelliJ squiggles go away.
I have to ask: is it the dependency management, and/or is the shitty software depended on?
The best dependencies are ones that don’t change. I learned yesterday that Guava’s
HostAndPort#getHostText
was renamed togetHost
for effectively 0 reason and, of course, we had code that we want to run with multiple Guava versions calling that method: a choice a dependency made turned into a NoSuchMethodError for me. Gradle is a good enough build tool that I can slap hacks where I need them.I am very curious to know what dependency management for Elm is like, with their auto-updating-semver for packages. Sounds like it could go really well or really bad depending on how it’s implemented.
There are good reasons to do simple renames of APIs (consistency being the big one). I really liked the way go handled this, with
go fix
tooling to do the substitution.In Java, this kind of thing is much harder. If the class or method are not
final
then subclasses might override them, so renaming is more than a simple text substitution.friends don’t let friends use guava!
Whenever I have a chance I remove it from code-bases. apache-commons-* is usually good enough. guava is not worth all the grey hair it is causing.
What’s wrong with using 4 different versions of Guava? It’s a waste of space, but what actual problems does it cause?
Nothing intrinsically, the complexity comes from building modules we want to work with old code that could be using any one of these versions of that dependency. For some of these, we choose one version to build this module against and fix up NoSuchMethodErrors when we see them. Other cases we do more hacky things to ensure field/method access is checked at compile time. You’d effectively have the same issue in any other language + build system.
guava is using semver, but they are using it to an extreme. Basically every release is a new major version, so anything goes. An API that worked in version 21 is gone in 22. There are very little or no guarantees. The thing is that the build tools assume that this is not the case. It is even more fun when you learn that sbt, gradle and maven all have different dependency resolution algorithms/order meaning things that work fine in one tool, breaks in another.
Simply put, having two libraries that depend on different versions of guava is a ticking time bomb and things may break or not. There are no guarantees.
While this is all probably okay w.r.t. semver, this is not what people expect from libraries that are basically used everywhere.
If multiple versions of Guava is a “ticking time bomb” for sbt/gradle/maven, it seems to me (coming from Rust world, where multiple versions are common and well supported) it is sbt/gradle/maven that is broken, not Guava.
well, guava is by far the worst library in the eco-system with this behavior. Sure dep. resolution is problematic in java land, but there is something to be said about a library being backwards compatible and reliable.
It is not good practice to behave in the way the guava devs are behaving. Aloso “fixing” java dep resolution everywhere is a lot harder than avoiding guava.
edit: I want to add that rust had it easier because they could see what works and what does not when they build out their tool chain. In java things have grown organically and there is not one single blessed way of doing things. That makes them hard to compare imho
Not sure what the author means by “the ecosystem is essentially a microcosm of the US political landscape” but it sounds awful. I never got much into Scala. I loved Haskell and liked Java but the hybrid form wasn’t for me. It seemed to me, at the time, that either you were worried about Java integration, or you weren’t, in which case you got to use ScalaZ.
The dependency hell he’s describing, I think happens similarly with Java and Python anyway.
[Comment removed by moderator pushcx: This kind of "everybody is familiar with an incendiary topic" is effectively trolling, don't do it again.]
Can you not?
[Comment removed by moderator pushcx: Pruning down the argument.]
[Comment removed by moderator pushcx: Don't smear people with a big brush like this.]
Or maybe he just didn’t know. Don’t imply people are fascists just because they don’t know about niche community drama!
Or, he could literally spend five minutes on Google and get all the context and content he wants instead of defending something he knows nothing about first which makes it look like he’s in support of them. Lobste.rs, like Reddit and others, is social media, and I don’t expect every person to list the entire history and context of everything they reference in their comments.
Here’s some context, John De Goes (JDG) invited a literal fascist to a conference with widespread opposition. Got banned from another ecosystem in Scala. This blew up in 2021 and Martin Odersky (BDFL) voiced support of JDG.
https://contributors.scala-lang.org/t/politics-safety-and-the-future-of-scala/5317
For the record, hereby I also voice support of JDG. Curtis Yarvin wasn’t invited to speak about fascism at LambdaConf 2016, he presented a technically interesting work which was appropriate for LambdaConf. By all accounts, except for boycott of Curtis Yarvin, there was no problematic incidents whatsoever at LambdaConf 2016, including behavior of Curtis Yarvin, who behaved polite. I stand against insanity that is cancellation.
Hobby projects aren’t technically interesting work. Grifts are technically interesting, but we shouldn’t let the original authors of the grift be the ones who explain its technical merits, since they are incentivized to continue the grift.
[Comment removed by moderator pushcx: Don't assume everyone is as informed and agreeing with you about giant hard topics.]
Your assertion may be true, but saying it without explaining why it is true is not conducive to conversation, and does not help others to understand. There are no points here to be won; this is no battle to slay one’s enemies. You simply have an opportunity to share – to explain why inviting a fascist to a community event is a bad idea. Don’t miss this opportunity to calmly and thoughtfully explain.
I do understand that some people, reading this, will have no desire to understand your point (just Ctrl-F for the term “cancel”). They will refuse to understand regardless of how carefully and thoughtfully you explain. Your job is not to attack them; if they wish to remain unconvinced, you must allow them to live unconvinced. Let them be.
Your job is to help others who are reading, who are willing to consider your reasoning but do not yet fully understand the topic, why inviting a fascist to speak at a community event is dangerous and/or damaging to the community. Why is it so important, in your mind, that we draw a firm line on this topic? What damage could be done by not drawing that line? Explain, patiently; it is an investment of time, but your written words will outlive us all. And try to honestly acknowledge what the difficulties and costs are of drawing that line.
Peace.
American politics has been the plague lately. 😢 So it sounds like the Scala community hasn’t been able to dodge that topic, either. There have been a few crazy-big-blow-up community issues lately, including in Haskell a couple years back.
On the technical topic, I’m curious if anyone has encountered any good solutions for “dependency hell”. Let’s assume that you are using a language with a vibrant community, and libraries aren’t massive monoliths (i.e. lots of libraries, composed of lots of other libraries, with a complex dependency graph). Do any language handle this well? Or if not languages, do any library managers handle it well? (Or …?)
It’s something I’ve lived through more than a few times, so I have my own proposed solution to it, but I’m curious how other people attack it.
NPM (javascript) solves this problem by installing transitive dependencies underneath the libraries that depend on them, and preferring to resolve dependencies from a peer level node_modules folder first and walking towards root if a match is not found. So if I depended on left-pad, and also another library that depended on a different (non-semver compatible) version of left-pad, when I install dependencies the directory would look like
and my application would resolve left-pad@2.0.0, but other-library would resolve it to left-pad@1.3.0.
This results in the massive node_modules directories that everyone loves to complain about, but it does solve the problem and disk space is cheap.
I think Rust works fine. Rust allows multiple versions of the same package in the dependency tree. There is no conflict because different versions get different name mangling.
Yeah… I think the alternative of keeping tabs on duplicated dependencies is by far preferable to being blocked on an impossible to resolve dependency conflict.
It’s perhaps too early to tell, but my experience is that the Go ecosystem has done well here. I don’t know if I’ve just happened to be lucky in picking libraries maintained by careful people, or if it’s actually some real difference. But, I’ve had a good experience, compared to other languages I’ve done significant amounts of code in.
Random thoughts that may affect experience
[Comment removed by moderator pushcx: Removing subthread that doesn't improve this hard topic.]
[Comment removed by moderator pushcx: Removing subthread that doesn't improve this hard topic.]
[Comment removed by moderator pushcx: Removing subthread that doesn't improve this hard topic.]
[Comment removed by moderator pushcx: Removing subthread that doesn't improve this hard topic. Why would you think adding religion to a discussion about fascism would _improve_ things?]
I promise the dependency hell situation is worse in scala