Scala isn't fun anymore
alexn.org
alexn.org
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
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.
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.
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.
sorry, but you can do that shit anymore:
https://wikipedia.org/wiki/Open_Software_License#Network_dep...
> 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.
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...
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.
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!)
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 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
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.
https://mvnrepository.com/artifact/com.typesafe.akka/akka-ac...
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.
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.
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 it, and the pricing scheme makes it very difficult to offer lower margin services and presents the company with potentially nebulous costs depending on how successful it is.
It's not just about paying. There's so much crap that can happen when you build your stuff around something proprietary. I'm not saying Lightbend will be like Oracle, but companies literally spend lots of money building proofs-of-concept using other databases to get negotiating leverage with Oracle - "see, we ported part of our thing to Postgres so unless you give us a good deal, we'll just replace you." At what point would my company start doing that with Lightbend and wasting my time as an engineer on nonsense? Does Lightbend end up having a "we caught a whale" mentality if my thing takes off or would they say, "oh, we're happy you're successful and we'll cap your license fees at $25,000/year - you clearly shouldn't have to spend millions a year paying us"? Lots of people have talked on here about building your product on someone else's platform. Usually that's about building on Facebook or Twitter who might cut off your access. Often enough, we talk about proprietary databases and lock-in worries. Building on a proprietary library like Akka isn't that different. You're going to be beholden to Lightbend.
I do think that we are too averse to paying for things, but I also genuinely fear the land-and-expand strategy that so many companies have. Maybe it's just $10,000/year today, but that could easily skyrocket under certain circumstances - and it's not always easy to migrate off something once you're on it.
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
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.
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.
The Java 9 Modules architecture would have been an opportunity to introduce something like that, but alas they didn’t.
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.
A configurable middleground is needed, but it's not an easy task to get that done.
Best bet it to be picky about dependencies that respect backward compatiblity or do name changes (like commons collections4)
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.
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.
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.
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).
Scala just adds more drugs to the cocktail.
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.
[1] - https://www.jbang.dev/documentation/guide/latest/dependencie...
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.
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.
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.
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.
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 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.
You really feel like you can do anything with it lately.
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.
* 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.
https://www.learnrxjs.io/learn-rxjs/operators/combination/ra...
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.
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!
But it's the difference between whether this statement is objective, or subjective.
> is the best concurrency library on any platform
I understand why people who like monadic constructs don't like it though.
I agree algebraic data types could improve this. I don't think monadic result types or exceptions would be an improvement.
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.
You wait for the first result using i.e. a shared result channel, then you cancel the context.
It's why almost anything outside the BEAM can't make that claim.
I guess a merge of Scala as the language (because honestly, Erlang & co suck) and BEAM as the platform would be awesome!
(Disclaimer: I haven't used Gleam, I just know it exists.)
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).
This is completely false. Years ago we (7mind) added async stack traces to ZIO. Now both Cats and ZIO support them.
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.
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.
> 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.
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."
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).
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.
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.
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.
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.
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.
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.
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.
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.
The older I get the more this rings true. I've had several false starts with fancy new languages and consistently yearn for the simplicity (relatively) and lack of choice the old times had. I've been programming a lot of personal projects in C because of that. Rust is cool but too much headache and still too "fresh" to be more than just an academic exercise for me. Go is the same, except im actually insulted at how limited I am with it. etc. Yea, this is probably me getting old. But I like to have one or two languages I can get things done with it. I've been programming Python since the early 00s in one form or another betting on it replacing Perl, and C has always had a charm to it C++ could not give.
Twitter specifically was designed in a time when RoR was really popular, but I'm not sure it worked _because_ it was built in RoR, and we all remember how twitter still exists simply by the grace that they managed to rewrite themselves away from the fail whale before competitors woke up to match their feature set.
Now it's written in scala and, to me anyway, I see hundreds of developers and I'm not _at all_ impressed by their development momentum, even though it's written in scala.
So, if that isn't the competitive advantage, why go for it in the first place? At least blue collar languages have much, much larger pools of competent programmers to select from, which is an objective, convenient upside any manager can understand.
I think its like Haskell, Rust, Go, Erlang, etc. These languages are extremely useful in the microcosm of places where they excel. Rust when you absolutely need to insure memory safety, Go when you need near-C speeds but a simple to use concurrency system, Haskell for rigid typing, Erlang for high availability, etc. The problem is the dead average developer looks at these, and sees these high flying companies doing cool things in it, and then decides "wow I should write everything in this - it's the future!"
Scala is the same way. It's not objectively better than a modern java in any way which might be taken as fighting words. But foregoing a lot of developer history you gain the power to reason about a very, very small subset of programming easier at the cost of speed, time, etc. For a company like a twitter with a very specific use case for this it made sense. Especially since at the time twitter switch from RoR to Scala, Python and it's concurrency platform didn't exist. However, I would speculate if they switched today they would've almost certainly gone to Python which would have been a much less "cool" switch and probably not even made the news cycle.
In practice the answer seems to be C++, maybe Rust. I'd happily use a "simpler" language like Go, Java or Nim, but something doesn't quite match the spec.
I think, unsurprisingly, languages are designed around common use cases, but the uncommon ones are there too.
Very much doubt it re: Python. Performance, difficult to reason about, and lack of static typing all come to mind.
I agree that modern Java is competitive now, but it probably wasn't when they picked Scala.
I saw projects (non-Scala) come to almost a complete stop from velocity perspective, because engineers were afraid to change old code. This resulted in many iterations and a lot of slow testing until changes were delivered. In my opinion, it can easily impact business side of things.
The same thing happened years later in another startup in Elixir. I arrived to this startup and there was some random microservice that someone had implemented in Elixir because it was "the new cool language that solved all scalability issues". Again, the person that implemented it had left years ago, so nobody knew anything about Elixir or the microservice. Because I've dabbed with Elixir for fun, I volunteered to work on it. In the end we decided to supersede it.
I've learned to stay with boring technology. For me the sweet spot of productivity and team versatility is TypeScript and Javascript. Using these two technologies devs can do backend, frontend and mobile. The only thing missing is good bindings for Machine Learning.
How does the effort of tweaking them in an unfamiliar language years later stack up against the effort they would have required otherwise?
Thus, the stuff they wrote were well written.
After they leave, nobody can improve it or change it. (See sibling reply).
It's the people, not the language, that produces good software.
And reverse of that worked for Perl, then PHP, then JS (and arguably also Python/Ruby)
I suspect this would be deeply embarrassing + would lead to change
in my (limited) experience, large scala codebases are not productive
scala adoption was all like 12 years ago and driven by bored developers looking for a brain teaser / resume builder. same trend as companies like linkedin / uber, who have no reason to invent infra, contributing a bunch of half-baked java projects to apache
Like Kafka and Samza?
I haven’t heard a developer being excited about writing Java in a long time.
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.
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.
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.
And, of course, you have a peer-reviewed article to support your statement?
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.
That said I:
• had zero C# experience and it was the C# interop that caused me the most pain. Its easy now but I didn't grok how to properly pass arguments to overloaded C# methods (i kept messing up parenthesis, commas, and didn't pass argument names to tell f# the right function signature)
• have been coding for 8 years
• have functional lang experience with elixir and elm.
Now f# is my primary backend language.
Even if you eventually decide you can't commit a team to F#, it's highly worth it because doing at least one app in F# will vastly improve your C# and how you structure applications. [2] I personally just got addicted to the expressive power, it's hard to replicate with any other ecosystem given the full power of .NET under the hood. Giraffe is also a great place to start if you know ASP.NET Core. [3]
[1] https://www.amazon.com/dp/1680502549
Now, OOP became a curse word, and if you do not do purely functional code with tagless-final and don’t know the definition of free monad by heart, you have no business writing Scala code (I like pure FP too, but if I want to write Haskell code, I can do it in Haskell), and the community drama with “typelevel/cats vs Scalaz” and “typelevel vs zio” was too much for me to handle. The new community is too toxic for me to continue writing anything in Scala.
The only bright point in Scala is lihaoyi’s ecosystem, which is sane enough to actually use, but it is too much to maintain for a single person, and it is losing momentum.
So I quit, and moved to Common Lisp, which is interesting and pragmatic enough.
However, Li Hayoi's libraries aren't a silver bullet. I could also argue something like "if I wanted to write exeception-throwing Java code, I can do it in Java." I use http4s/fs2/CE because of the better ergonomics, and I never needed to learn what a Free monad is.
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.
2. In my experience, having up-conversions between different monads is intuitive low-noise
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.
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.
I think I can! I mean, that's what science is for, right?
This is what makes Scala good. The language itself is not very complex actually, but it enables complex and powerful libraries.
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.
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.
> 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...
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.
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.
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?
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).
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.
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.
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.
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.
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, ...
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.
1. https://openjdk.org/jeps/425
2. https://openjdk.org/jeps/428
3. https://medium.com/helidon/helidon-n%C3%ADma-helidon-on-virt...
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".
> 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...
> 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...
> The network is reliable.
[1] https://www.computing.dcu.ie/~ray/teaching/CA485/notes/falla...
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 is: sync calls don't change. Async calls use the Future::fork call, all within your parent thread block scope.
Because otherwise your claim "sync calls don't change" is wrong - since this is how it currently works.
Basically, you don't have a thread context anymore, or you don't have a use for it anymore
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.
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.
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.
What I mean is that semantics of existing code changes (and becomes harder to understand for future code).
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.
That's exactly what Loom is.
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.).
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.
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.
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.
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.
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.
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.
Suffice to say there's a lot of people at each others' throats, and it probably won't get better.
Hell the worst thing the Scala Discord deals with it are spambots!
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.
[1] http://meta.plasm.us/posts/2020/07/25/response-to-john-de-go...
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.
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.
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.
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.
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.
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.
However trendy programming has very much become pointlessly complex.
Perhaps it's better now.
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.
But having said that, this paragraph jumps out as completely perplexing:
"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. I’m guessing all programming communities are turning to this nowadays. As an Eastern European, however, it kind of pisses me off."
Please don't tell me there are political camps in FP now.
All nontrivial groups of humans end up with political camps. If you don't notice it in a space, it probably means that there is one dominant political camp and it is the one you are in.
Nope. Well, politics is pervasive because politics is just the word we have to describe how people in groups interact. I'll summarize the situation:
There's a very small minority of prominent Scala people that are fine giving space and a platform in the community to people that are known white supremacists. [1] It's unfortunate that they're decided to inject their brand of politics into the Scala community. The community has had to respond by adopting codes of conduct that compel members to act with basic decency and morality.
[1] http://meta.plasm.us/posts/2020/07/25/response-to-john-de-go...
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.
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?
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.
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.
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.
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.
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.
- 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.
I don't write Python, but Python is like Java these days, it finds you.
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.
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.
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.
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…
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.
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.
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.
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?
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...).
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.
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.
what does this mean?
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.
Travis one of the guys involved has even left Scala to do his activism work full-time.
https://typelevel.org/blog/2019/09/05/jdg.html
https://meta.plasm.us/posts/2020/07/25/response-to-john-de-g...
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?
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.
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.
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.
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.
> (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.
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?
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.
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 smaller than Scala's. Not by much though. They're both just tiny. Well, not JS-level tiny. Probably somewhere around Scheme's R7RS or OCaml.
> and heavily inlined in comparison.
Again, Scala compiler is supposed to be "intelligent enough" to produce code faster than hand-written Java in some cases! How come such a compiler has problems inlining the code of stdlib, arguably the most optimized code of all in any language? What weird things are happening in that stdlib that the compiler has such a hard time inlining them?
> On a mobile platform, this matters.
Sure. But you just said it doesn't matter for Scala, because it's happy powering server middlewares and big data frameworks, even if it means loosing out on a lot of mindshare, contributors and all that.
[1] https://en.wikipedia.org/wiki/Matthias_Felleisen
[2] https://racket-lang.org/ and https://docs.racket-lang.org/drracket/interface-essentials.h...
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.
(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.)
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 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, really.)
> Today, 70+ people work on the core Kotlin project team at JetBrains
https://kotlinlang.org/assets/kotlin-media-kit.pdf
Plus a bunch of Google employees working on Kotlin stuff like the new K2 compiler.
I mean, that's how we got languages like Ceylon, Fantom or Kotlin.
Scala the ecosystem was never fun though. I can’t decide if it’s worse than JavaScript (NPM upgrade hell sucks hard).
”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. I’m guessing all programming communities are turning to this nowadays.”
It's also a very US-centric kind of political battle that I'm sure a lot of European Scala programmers feel is strange and doesn't apply to them, but has nonetheless taken their ecosystem by hostage.
Actually, it wasn't the "committee" that allowed it, it was a subset of speakers from under represented groups in tech (women, minorities, PoC etc whatever term you prefer) that voted to let him speak as long as he kept to his topic.
I have no stake in the process here. As I said, it was clearly well thought-out. But the outcome is regrettable.
1. Emphasis on API stability.
2. Simple dependency management that generally just works.
Having to change my global git config (e.g. https://gist.github.com/dcyou/06a4f6e0a770887fbd01fa8276b945...) to cater to Go is asinine.
The way that it deals with dependencies seems to fix a lot of the problems that the author has mentioned.
The Akka BSL is a big disappointment to me as well but a better name for that would be LightBend isn't fun anymore.
Gatling achieves it's relative low-overhead characteristics (compared to a naive approach like JMeter's) by leveraging Akka. Does this mean Akka lawyers will be coming for Gatling customers, or will they go after a slice of Gatling's pie?
Either way, hopefully someone will reproduce the Gatling functionality on the JVM using the Loom programming model. Then we can wait a few years and start the whole dance again.
I don't have a workable solution to propose. I guess I'll just quietly polish my dancing shoes and get ready for the next song.
Also, he does not mention Chisel.
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.
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.
Later, we need to recruit more people, it became harder and harder. Each need to learn a lot before they can contribute bug fix to product. They need to learn:
- Scala
- Akka
- very basic of sbt (if they need to change more than basic usage, they come to me for that change, as I'm the only one who learned complex sbt syntax in our team currently)
- Play framework
- Slick
But now, several years later, Akka's license change really make us to consider switch back to plain Java and Maven one part by another. For the actor model, I really like it, it can simplify Synchronization A lot, we researched Vert.X, which seems can do most of Akka (Although I haven't research whether Akka Clustering, persistent can work similar in Vert.X yet).Regarding Akka - let it rest in peace, it was one step ahead and ten steps back. Actors have too many fundamental problems to be a good general-purpose model.
You don't? You chose to read the article yourself of your own free will. At least, I hope you did.
2. I don't believe that scala-native was a good idea in the first place, because of all the java-interop boilerplate already present. C/JVM interop design conflicts are very hard to abstract properly. It would've been nice to adopt some WASM-compatible IR instead of MLIR/LLVM lock-in.
3. WASM-first is a very viable AOT+PGO option, it also brings new opportunities for remote exec and some interesting Architectural Approaches like automagic splitting monolith into microservices on the fly by potentialy calculating communications overhead and performing basic discrete optimizations.
So, Scala is still fun, just missing a lot of business oportunitites, it's just that Odersky decided to take another spin of EU Grants acquisition by developing a new lang.
I, personally, don't think that dotty was "good enough" to roll out last year, but overall project traction and cash-flow directions don't look that promising. And I personally choose to call it EU Budget Laundering, because it's really puzzling for me how exactly 60mil Euros grants are not enough to make Dotty stable. If no-one audits than no-one cares about it, or how does laundering and embezzlement work nowadays ?...
From a lang design standpoint, there are three things which make Scala obsolete
1. No proper formal verification - although there are things like stainless (stainless.epfl.ch) and it would've been possible to adopt zero-GC alloc during codegen by adopting CoC similarly to neut (github.com/vekatze/neut)
2. No proper support for protodef and IDL's - nowadays efficient serialization (marshaling) defines software reliability, all these JSON'y/Protobuffy/Flatbuffy thingies really causing some traction, although every single one of them are not something I'd call scalable.
3. Adopting Calculus Of Constructs (CoC) and formal verification alongside bunched-separation logic (like in F-star lang and rust) should be enough to formally prove Mem consuption, amount of IO and the respective computational overheads. Basically it would've worked similarly to CAP: pick either small mem footprint and bandwidth needed - the amount of compute power and the respective latency will be calculated and formally proven.
The exact desings of separation logic for multi-threading apps is a complex subject, but I like what Azalea Raad done with Concurrent Incorrectness Separation Logic (CISL) - it's something that would've allowed rust, for instance, to drop it's boxed types for RAII and a lot of the existing sync primitives (Arc, Barrier, Condvar, PoisonErr etc).
But who am I to talk about that... I never boiled in the Sciency Kettle and Played by the Academic Tribe Rules, spending half of my life just to copy-paste generic paperworks from here and there, filling up the gaps by slaving the Kenya/Nigeria students on forced contract terms, with usual threats, IP Extortion, common worker-contractor misclassification.
Everything professory Academic-related looks so corrupt for me nowadays.
Anyone thinking about porting Play to another framework?
I don't have an extremely strong argument that this is the root of many of his problem with version mismatches, but I do have a strong hunch that it is.
I've spent a little bit of time with Scala, a little bit with Clojure, and a lot with Kotlin. My biggest conclusion from all these years of working with non-Java JVM languages is that Java interop is actually a language mistake. Or, rather, Java interop ends up being "design debt". It's great to bootstrap your new JVM language into popularity because people can try to gradually switch from Java or use mature Java libraries when your $NEW_LANG ecosystem is still nascent. But, the problem is that Java libraries are written in Java style and are written within the constraints of Java and Java's type system.
The most obvious (albeit likely the least problematic) example is null in Kotlin and Scala. Both languages have superior ways to handle the "bottom type" to Java, but a Java library obviously doesn't get to use those.
The other problems come from how much information can be expressed at compile time. The biggest design flaw in Java as a language is that it combines type-erased generics and runtime type reflection/inspection. Either one of those is fine, but they are quite literally incompatible concepts. You can't apply type-based logic on a type that doesn't exist.
Yet, because of how unexpressive Java's type system is, any sufficiently complex Java library/framework will make ubiquitous use of type reflection. Usually while leveraging annotations.
I can't tell you how many type bugs I've found in the JacksonXML Kotlin compatibility module and in Vert.x with Kotlin. Nulls sneaking in where they aren't supposed to, value classes randomly causing issues because something boxes up a Function object and then uses reflection somewhere surprising, things not serializing correctly because JacksonXML or Gson doesn't understand some perfectly valid type I've defined, etc.
But something like JacksonXML should never exist in Scala. Scala has type-classes, so you can define your serialization and deserialization logic on the type itself. Then it can be checked at compile time. For Java, defining and passing around a separate serialization object for each type would be too cumbersome, so all of the serialization libraries use reflection and just hope they can figure out the deserialization at runtime. When you find out that it can't because your app crashed, then you can backtrack and "teach" Jackson/Gson how to deserialize your troublesome type with a custom deserializer class and an annotation.
And it's not just the type systems being incompatible. It's also the style and idioms. Java frameworks really like to be "magical" and hands-off, because it's so verbose to define and pass around separate classes for everything.
I believe this is also manifested in the OP's issues with libraries depending on other libraries and causing version conflicts. If Java libraries were less "plug and play", they would ask the user to provide logic, instead of saying "Don't worry, I'll do everything for you under the hood."
Is this just a cliché Java flame comment? Maybe it is. But it's based on my many years of dealing with Java and every popular JVM language (excepting Groovy; I don't have any experience with it outside of gradle).
I now have a policy that if I'm working on a Clojure, Kotlin, or Scala project, Java dependencies are nearly forbidden. It's a very high bar to include a Java library dependency, and if it uses generics or reflection, it's basically an instant "no".
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...
Yikes! It's unbelievably exhausting to hear white folk say that they don't want to deal with the consequences of European colonialism.
Racism exists. You can either be anti-racist or pro-racist. There's no middle ground when everyone lives in a society that is built on the backs of hundreds of years of stolen labor in inhumane conditions. There's not _one part_ of modern, global society that isn't affected by racism.
Remember, it's an extreme privilege to look at a part _real life for the majority of people on the planet_ and say "it's just politics."
The fact you just immediately went rage mode before asking questions just proves his point.
And yes, he's white. You can verify this for yourself by looking at the blogpost author 's About page, a video from a talk they did [2], and with their self-identification as eastern european.
I'm unsure if you meant to do this, but your comment comes off as gaslighting: you don't know what's going on and you asserted something that is false as true. Next time, if you're not certain about what's going on, I encourage you to do a little bit of Googling.
[1] http://meta.plasm.us/posts/2020/07/25/response-to-john-de-go...
[2] https://slideslive.com/38908144/a-tale-of-two-monix-stream
> I'm unsure if you meant to do this, but your comment comes off as gaslighting: you don't know what's going on and you asserted something that is false as true
No, I didn't make any assertion. I asked questions based on your attack on the author. You comment was completely out of context of the article, so it seemed off-base. I can understand if you have inside knowledge, but your reaction was still not a good look to the majority of people like myself who are not.
> Next time... ...I encourage you to do a little bit of Googling.
Your behavior is still illustrating some of the author's point. Some individual/group cultures are cesspools of unhappy/combative people. As someone who has no desire to 'pick a side' of a language community battle, I identified with the author's lack of enthusiasm for a particular community, without knowing all the details. There's nothing wrong with that.