This is a nice write-up, it's beeb some time since I've written Scala and Scala 3 looks promising.
Though, I am curious if there is anyone else who shares my mindset on Scala.
In a corporate environment, I found it to be an extremely expressive and powerful language but that power comes at a grave price, which I'll try to summarize:
- it's difficult to understand other people's code compared to other languages (e.g. Go)
- it's so very implicit that you end up having to hold a lot of state in your head to understand what's going on.
- the language is basically impossible to read effectively without IDE features.
I usually enjoy reading most code bases, but Scala is downright painful to read in plaintext. You end up having to be a compiler.
In a good Scala codebase you use the implicitness to put the business logic front-and-center and push secondary concerns into the background, but without making them completely invisible. The plaintext becomes something akin to the DSLs that people write in e.g. Ruby (using metaclasses and other such magic), but when you open it in an IDE (or compile it in your head) all those extra details become visible to you in a reliable way, rather than having to guess what a given piece of code actually does.
IMO modern language designers should be making IDE-first languages - after all, most serious programmers do use IDEs (even if they build that IDE within Emacs or Vim). The problems with "visual languages" are that without a textual representation you can't meaningfully diff/merge/blame, not that using the GUI is an inherently bad idea. With Scala you get the best of both worlds: it's textual enough that version control works properly, but you have standard-ish way of folding, hovering etc. that mean that you can "zoom in" on the details of unfamiliar code but also "zoom out" to get a clear overview, in a way that few other languages manage.
Agree. It's a shame because I do believe it is very much cultural - it is possible to write very clear, expressive and safe Scala code. But it doesn't seem the community has settled on that as a cultural idiom. Instead they frequently favor maxing out the power of the language and type system at every opportunity and that means you often encounter lines of code that look like a string of hieroglyphics, or functional programming concepts and higher order types thrown at basic simple logic that could be imperatively written with much more clarity.
AkkaHttp being the main offender imo. If something as braindead simple as "routing http requests" can't be expressed without magnet-pattern / 5+ nested levels of curly braces / odd-compile-errors / magical punctuation functions / 0-debugging then your library has failed.
If I can't understand the type of a route (or a db-query) because it's a 5-level nested type, how am I going to write a function that takes one as a parameter?
I agree with most of what you said, but for the last point, I think I can add a different perspective.
Because, once I got used to the (pure) functional programming style, I found it more difficult to mix this style with imperative code. It's almost always easier to for example use for example the state monad than writing it with mutation. This is probably quite subjective and it depends what you are used to.
For me, I make an exception for tests. E.g. when I mock my key-value database with an in-memory map, I choose a mutable map. But I know that some people prefer FP style even for tests.
> - it's so very implicit that you end up having to hold a lot of state in your head to understand what's going on.
I wouldn't use the word "state", since that has connotations that implicits are somehow changing at runtime. It's certainly true that scope is much more important and non-obvious than explicit variable names.
Type aliases can also get in the way when thinking about implicits (e.g. we might want an implicit 'Foo[Bar]', but if those are aliases then the compiler might start chaining Maps of Lists of Strings of whatever to resolve it).
Implicit conversions definitely seem like they could cause headaches (e.g. performing 'String' operations on a 'List[Char]' and having it implicitly and silently converted). I've only been using Scala for the last year, and thankfully implicit conversions seem to be avoided these days!
Scala is my favorite language, even though I don't work with it professionally anymore. And I've seen it all. And yes, bad code in Scala is probably harder to read than bad code in other languages. It can be outright painful. However, good clean code in Scala is easier to read IMO. I think it takes a strong culture and strict standards for an organization to adopt understandable Scala. Unfortunately, those organizations are rare and there will be people who will likely abuse some of the "clever" features of Scala. I've been fortunate to be in those organizations with good clean code (and places with unreadable Scala code).
Completely agree. I got to work with a Scala codebase for a few months, and those few months were painful indeed. It was well-nigh impossible to make sense of any pre-existing code.
I'm no stranger to diving into a new codebase and trawling my way through spaghetti to make sense of it ... but I absolutely do not want to do this with a Scala codebase ever again.
> it's difficult to understand other people's code compared to other languages
I think it depends a lot on the code. Scala 2 gives you a lot of guns to shoot yourself in the foot (see: implicit, as discussed here) - but you can also use it in its mostly-functional form, with immutable values, and then it can become very readable. Granted - I've always been using IntelliJ but I could read the scala code on Github too, just fine.
To make sure everyone can understand each other's code in a corporate environment, use strict linting (scalastyle, wartremover) and formatting (scalafmt).
This is necessary, but definitely not sufficient, I'd think.
Oftentimes one stares at a mile-long chain of methods on a list and is left wondering "exactly what did the original author want to do here, and why are things breaking"? In the end, the only way to find out part of the answer is to exercise the relevant codepath via some test data (if you're lucky) and use IntelliJ's excellent debugger to help you move forward. Even this just reveals the "what", not the intent.
No amount of consistent linting or formatting can make this better. And no, ExpressivelyVerboselyNamedFunctionsInAidOfSelfDocumentingCode don't help either.
Though, I am curious if there is anyone else who shares my mindset on Scala.
In a corporate environment, I found it to be an extremely expressive and powerful language but that power comes at a grave price, which I'll try to summarize:
- it's difficult to understand other people's code compared to other languages (e.g. Go) - it's so very implicit that you end up having to hold a lot of state in your head to understand what's going on. - the language is basically impossible to read effectively without IDE features.
I usually enjoy reading most code bases, but Scala is downright painful to read in plaintext. You end up having to be a compiler.