I can give plenty, but I'll try to keep it short. First, what is the problem Scala is trying to solve? I know that Erlang and Clojure try to solve the problem of writing concurrent code (and fault-tolerant code in Erlang's case). Haskell tries to make writing correct code easier. Ruby and Python were made for ease and productivity, and both Ruby and Clojure are great for DSLs. Java and C are used nowadays for performance, and Java is relatively good for architecting huge software systems.
What is Scala for? If I'm hard-pressed to give an answer, I'd say, "better productivity than Java, in a statically typed language, with good performance". Now that's great, and Kotlin is all that, too.
Why the immutable data-structures, then? To make concurrency better? In that case, why is mutability just as easy? And what are implicits and these new cringe-inducing macros for? DSLs? Why would a high-performance, statically typed language make it easy to write DSLs? Is it to introduce developers to the wonderful high-level abstractions of FP? Why all the OOP, then? Oh, it's to combine the too; in that case why do they feel so strenuously glued together (classes vs. case classed, an entire collection package replicated twice, once for the mutable case and once for the immutable).
So the language offers a powerful compiler but absolutely no guidance on how a program should be written. If at least Scala had somehow provided all of these features and stayed elegant, but man, it would take you weeks just to understand how a freaking Scala collection works, just because the language designers wanted to be so clever and prove that you could transform collections and still never require casts. It seems that at every turn Scala favors cleverness over clarity, and features over a cohesive philosophy. Scala chooses, over and over, to try and address more goals (most are really unimportant), and in the process has lost the most important thing in a language: coherence.
Scala sees something nice in another language and immediately adopts it. And I gotta say, writing a compiler that compiles code that's both javascript and Haskell is an impressive feat of engineering. But it comes at such high a price...
I think it is totally OK to dislike a language for pretty much any reason, but that wall of text reads a lot like “I never actually used the language, but here are some things I read on the internet which sounded plausible to hate”, which is quite disappointing, imho.
I've had a long history with Scala, but have only written about 500 lines of code using it. My feelings towards it had this trajectory: great hope, realistic hope, caution, suspicion, confusion, disappointment, pity.
Around 2006 I was working at a pretty large Java shop, and had hoped to convince the whole organization to gradually switch to Scala. There was one thing that really bothered me at the time, which was the inclusion of XML in the language. I wasn't too fond of XML, didn't think it would last, and thought it a sign of thoughtless trend-following on the part of the language designers, but I liked pretty much everything else. I really liked traits, I liked pattern matching; I really liked lambdas. I thought the language would never win any points for elegance and grace, but at least it was powerful. In any case, the language was young, and I knew I would have to let it mature before there was a real chance of it being adopted in such a large organization, so I kept close tabs.
Shortly after, implicits were introduced (if I have my chronology straight), and I then noticed that scaladoc only made an API even harder to understand, but I thought this could be resolved. Then structural types were introduced, and a big red warning light went off in my head. By 2009-2010 it was clear that a large organization like the one I was working at, would never adopt Scala; it was too unwieldy. Then collections were revamped, and Scala became the only language in existence whose automatically-generated documentation ensured that an API could never be understood. The designers' taste, or lack thereof (taste means choice; preference) was clear. I was then introduced to Clojure and learned that an extremely powerful language can be extremely elegant at the same time, and that a language can really help you program (rather than confuse you with "constructs") by adopting a coherent philosophy. I pretty much abandoned any hope for ever liking Scala again (or recommending it for a large organization), but I swear to you that I still thought, "the Scala guys haven't adopted macros yet in spite of their lispy awesomeness; perhaps there's some hope to them yet; maybe they finally realized that mixing ice-cream, steak, and pizza in a bowl does not make a good salad". We all know how that turned out.
I think I'm a pragmatist, but leaving aside the total incoherence of Scala, it has become so inelegant, so ungraceful, that I wouldn't use it for that reason alone, especially considering that most modern (and non-modern) languages value elegance. It's as if C++ hasn't taught us anything; as if programmers need to make a binary choice between power and beauty.
In the meantime, Scaladoc has actually improved, but that's just too little too late.
There was one thing that really bothered me at the time,
which was the inclusion of XML in the language. I wasn't
too fond of XML, didn't think it would last, and thought
it a sign of thoughtless trend-following on the part of
the language designers, but I liked pretty much
everything else.
Good news: You'll be able to delete the scala-xml.jar file. Done. No XML support in the language.
Then structural types were introduced, and a big red
warning light went off in my head.
They are a simple generalization and remove arbitrary restrictions on what can be a type and what can't be a type. A win for consistency.
They will become crucial if you want to interoperate with prototype-based languages (JavaScript for instance), so I think the language designers made all the right bets back then when we see the hype around JavaScript today.
I don't use structural types much, but a lot of people seem to so excited about them that they designed the whole language around that concept (Golang).
I then noticed that scaladoc only made an API even harder
to understand, but I thought this could be resolved.
Scala became the only language in existence whose
automatically-generated documentation ensured that an API
could never be understood.
I don't understand what you mean. Could you explain?
I think I'm a pragmatist, but leaving aside the total
incoherence of Scala, it has become so inelegant, so
ungraceful, that I wouldn't use it for that reason alone,
especially considering that most modern (and non-modern)
languages value elegance.
As someone who actually uses the languages and undertakes a lot of comparisons with other languages to better understand the state of the art and existing solutions before designing APIs, I totally disagree with that.
There are not many languages out there which consider consistency and elegance to be as important as in Scala. In Scala things can and will be rejected or removed for failing to live up to these standards alone.
Your effort is very much appreciated. There, I upvoted both well thought-out answers.
I would never say that Scala's designers are stupid. Far from it. The Scala compiler is a work of brilliance. And, obviously, every feature, as you so meticulously tried to present, has a purpose; tries to solve a problem. But your explanations, I feel, only prove my point. Many of your explanations are along the lines of because sometimes you need that ("Some algorithms work best", "a good tool to solve some problems", "for some things it make sense"...). While absolutely true, and every practical language, be it a programming language or a spoken language, needs versatility and irregular forms, it seems like Scala tries to take on each one at a time rather than spending most of the intellectual effort on defining the common case.
For example -- and this is an important philosophical point of disagreement -- you say of macros: "... instead of having to resort to such terrible things as annotation processors, bytecode rewriting and Java agents." This, imho, the WRONG answer. Those problem areas that in Java are addressed by what you call "terrible" means, are highly irregular; highly uncommon. They should be addressed by "terrible" means if your goal is a simple language. Yet Scala seems to want to address every problem with a language feature, and in this case it's a huge one.
On the other hand, when I look at Erlang and Clojure (or Ruby, though I'm less familiar with it), I see languages that were designed by people who sat down and thought long and hard about which are the top one, two or three most burning problems of software development, and then tackled those and only those. Everything else would be solved possibly "terribly" (though it would be solved). Rich Hickey thought long and hard and came to the conclusion that while OOP might be the right solution sometimes, in the end it's more trouble than it's worth, and people should not generally use it to write most programs. He may be wrong, and he may be right, but he made a decision. He thinks (I guess) that if your particular problem absolutely requires OOP, then you're better off using a different language, one that's been lovingly crafted for that purpose.
This is extremely important. A coherent language says, "for my problem domain these are the tools you should use". A general-purpose coherent language adds "... and most problems fall in this problem domain". For whatever is left, use other, better suited languages. Scala never says this. For every problem, big and small, it tries to find a solution in Scala. I mean, it's running on the JVM for god's sake, and interoperability on the JVM is particularly easy. Why not come out and say, "DSLs are great; we absolutely love them; if you want to use them, write them in, say, Groovy"?
I did not intend to ask why would you ever need this feature or that? What I asked was, why must they all be in the same language? If you had said, "look, Scala just tried to do this, but because of sheer genius it just happens to do that, too", that would have been a good answer. But you didn't. Each feature is there to solve a different problem. That's why Scala lacks coherence.
A non-coherent language says, "here are the tools you can use". It says, "in your programming endeavors you might some day encounter this byzantine problem, and guess what? We got a tool just for that!" It lays out a huge set of tools, all usable at some point or another, all serving a purpose, but doesn't say "I think you should rarely use this tool or that, so I'm leaving them out of the toolbox. When you need them, buy them separately" (Worst of all, it gives you a bulldozer when all you need is a hammer. That's why it's unwieldy)
These are two competing philosophies, but for modern software development, the latter is the wrong choice and the former is the right one. Software systems are getting bigger and more complicated as it is, while programmers aren't getting smarter. Some challenges are much more important than others. Scala chooses to be Jack of all trades and master of none[1] in the very discipline that needs the opposite approach.
[1] What is the one or two things Scala is better at than any other language? For Clojure it's managing state; for Erlang it's fault tolerance. Both are at the very top in some other aspects as well. But what does Scala do better than anyone else? (and is that thing important? You might say it's best at marrying OOP and FP -- though even if that's the case I'd say being best doesn't mean you're good enough -- but I don't think that anyone would say that combining these two paradigms is what the software industry needs most. Or, you might say, typed OOP. But typed OOP is, again, a compiler feature, not a solution to a burning problem)
I think we have a major philosophical difference and talking a bit past each other.
Here are the two things why I am using Scala:
1. Confidence
Scala gives me the confidence that I can build software the way I imagine, I can focus on the user of my code, not on making the compiler happy.
While there are plenty of languages which make easy and medium problems nice to solve (Clojure and Erlang certainly belong to this group), Scala is one of the few languages which keeps supporting me regardless of whether my problem is easy, medium or incredibly hard.
In my experience, the work on making hard problems easier had a huge tricke-down effect which in turn improved Scala's issue solving capabilities for simple and medium issues.
I think the language is better for that and certainly ahead of Erlang and Clojure here.
While most hard problems are not common, they are often fundamental. Not being able to solve some issue in the best possible way can have huge negative impact on the whole application and library design.
That's why for instance making it easier to create macros wasn't the first problem to concentrate on. Instead, developers made sure that users of macros had the best possible experience and focused on having one, unified API for reflection, the macros and the compiler, hugely simplifying semantics while re-using battle-proven code.
Macros makes it possible to pull more functionality out of the language and out of the compiler; into libraries. For instance C# 5 introduced huge language changes with adding async/await to the language. In Scala no language change is necessary: Adding support for async/await would be just a library.
Unlike Macros in most other languages and inferior approaches like in Java, Scala macros are type-checked as regular Scala code at the definition site as well as the macro expansion at the call site, removing huge amounts of tricky issues all at once.
Great care is taken to make and keep Scala a highly regular language with only the minimal amount of hardcoding necessary to make things work. Unlike Clojure, it doesn't have special-cased syntax for collections and a few “blessed collection types” shipping with the language. Unlike Erlang, Actors are not built into the language.
In both cases, Scala avoids irregularity by enabling users to build libraries which can be improved and be replaced without much trouble.
Yet Scala seems to want to address every problem with
a language feature, and in this case it's a huge one.
This for instance is something I would call blatantly wrong. You confuse the distinction between a language like C# or C++ which adds tons of features to address every fashionable problem and Scala, which keeps its feature count low and orthogonal but manages to solve a lot of those problems by just being a better designed, more expressive language.
On the other hand, when I look at Erlang and Clojure
(or Ruby, though I'm less familiar with it), I see
languages that were designed by people who sat down
and thought long and hard about which are the top one,
two or three most burning problems of software
development, and then tackled those and only those.
Well, that's nice, but I think it is even better that some people decided to bite the bullet and improve a lot of things instead of just building yet-another-language which improves on parts which the creator found subjectively important and regresses on dozens of others.
Is it hard to build a language with these intentions? Sure! Is that a reason not to do it? Absolutely not.
I think one part where Scala has basically proven tons of people wrong is OO/FP. People have been saying for decades that OO and FP are fundamentally opposed to each other. Scala just went ahead and proved them wrong, showing that just because some earlier approaches like OCaml or F# are not that good doesn't mean it is impossible.
Also, people have been claiming that there will always be a impedance mismatch between languages and databases. Scala went ahead and showed that it has not to be that case.
I want the best OO functionality combined with the best FP functionality.
I want to be able to use higher-order abstractions combined with the best performance and efficiency.
I want libraries written in the best possible way, not in the way the language decided it was convenient.
I want to use the right tools for the right job without having to migrate from one language to another.
He may be wrong, and he may be right, but he made a decision.
It's 2013. Let's stop forcing people to make pointless decisions. I just won't choose between things if I can have both, combined into a consistent library.
Clojure or Erlang just don't deliver here and that Clojure is the best language to manage state is highly debatable, too.
I think you should rarely use this tool or that, so I'm
leaving them out of the toolbox. When you need them, buy
them separately
This is by the way exactly what Scala says. The language ships with the tools to enable people to build libraries. By default, everything is left out.
Don't take me wrong, a language should be as easy as possible — but not easier.
2. Community
It is pretty non-sensical to ask “What is the one or two things Scala is better at than any other language?”. There plenty of things it does better, because “good enough” is just not good enough for people in the Scala community.
In general the Scala community is highly critical of every aspect and tend to push things to the current state of the art or beyond it if they feel something can be solved in a better way. This has led to a huge increase of consistency and quality throughout the ecosystem, so that having a few good parts and a lot of mediocre parts is just not acceptable to most Scala developers anymore. They demand the best tools one can possibly build.
Anyway, I think your use of “coherent” is getting more clear, but imho makes less and less sense. You are basically asking for a silver bullet and are unhappy that Scala tells you that for many problems, there isn't one. I think this is one of the core advantages of the community: It doesn't try to sell you some “ultimate solution”, avoids ideological bullshit and treats people as grown-ups.
For instance, Scala's Akka team (those who work on concurrency-related libraries) had an interesting talk recently where the demonstrated something like 9 different approaches/techniques to tackling concurrency, all of them with different benefits and drawbacks, with the main conclusion of “pick your poison”.
I think this is one of the core distinctions between Scala's diverse community and other, more anglo-saxon-centric communities: People who have grown up in the US just love to swallow shallow marketing non-sense and respond extremely well to claims about “one true way” or “silver bullets”.
If somebody came with that approach to the Scala world, people would tell him/her that he/she is either lacking experience, has poor judgement, or probably both and show him/her why he/she is wrong.
The way people carefully evaluate different approaches and document its pros and cons instead of following the next hype is exactly why I'm using Scala.
Scala's strength is shipping efficient, reliable and fault-tolerant software at a rapid pace.
Well, best of luck with Scala, then. I am aware that there are people out there who like Scala, some of them even like it for the reasons you mention, and some of those even seem to find it elegant (BTW, I watched a talk[1] by Marting Odersky in which he tries to explain why he thinks all those Scala features should be crammed into a single language; even he didn't seem half as convinced as you are :)). It's good to have choices in the JVM ecosystem.
I'm curious what you find it is about Scala that lets you solve hard problems that you don't find in Clojure. Is it static typing and/or OO support? I'm also curious what you don't like about having syntax literals for vectors/maps/sets?
For instance Scala's support for composition and modularization of library fragments which allows you to separate even heavily interwoven concerns into tidy parts and put them together whenever and wherever you like it (or exchange some parts of it completely)
Static typing is certainly a factor, too. Scala allows me to not only design APIs which make it hard to be abused or misused, it makes it possible to encode many things I care about into types so that “wrong” code won't even compile.
With macros, there is now a whole new breed of libraries which add support for types to tasks which were to get wrong before, for instance
- the whole type provider business where one points to soma data source (like a database) and tells the compiler to figure out the right types on it own
- compile-time checked and SQL-injection-safe string interpolation like sql"""SELECT * FROM PERSONS WHERE $predicate"""
- sqlτyped (github.com/jonifreeman/sqltyped) which can compute types from SQL strings
- macros which transpile Scala code to JavaScript, inline (jscala.org)
- macros which can synthesize typeclass instances on-the-fly, like used in Scala's new serialization library (speakerdeck.com/heathermiller/on-pickles-and-spores-improving-support-for-distributed-programming-in-scala)
- Scala's async library (github.com/scala/async)
Regarding collection literals ... it certainly isn't that important in languages like Clojure where performance is not of great importance, because everyone just picks the one which come with the language and hopes it won't be too bad. Implementing new collection types is just not common here (like in many other untyped languages like PHP, Ruby, Python, JavaScript, etc.).
In Scala, blessing a few chosen collection types with special rules and syntax just won't fly. Developers demand first-class support for all collection types including the ones they define themselves.
Reserving some special rights which no one except the language creators are able to use just gives them an unfair advantage. All implementations should compete on the same ground so that the best one can win, and not the one which benefits from special-cased, hard-coded syntax rules.
Let's just say that I have a bit more, up-to-date experience with the language and I value its consistency, coherence and elegance.
One thing I really like is that Scala pushes for more general, generic solutions, instead of ad-hoc additions and hacks: implicits instead of extension methods, traits (instead of abstract classes + defender methods), objects (instead of “static” members), types (without arbitrary rules about what is allowed as a type and what not), pattern matching via apply/unapply, for comprehensions via map/flatMap/withFilter, methods instead of methods and properties.
That tons of languages (Java, Kotlin, Ceylon, ...) are copying Scala's design decisions (often badly, but nevertheless) is another sign that Scala got a lot right.
Ok ... whatever, if I have already written so much, I can just answer to your claims one by one (I hope that the time I spend on this will at least be slightly appreciated):
PART ONE (Hackernews complains that it is too long)
what is the problem Scala is trying to solve
Being a modern, typed language which gives people the right tools to solve today's and tomorrow's engineering requirements.
I know that Erlang and Clojure try to solve the problem
of writing concurrent code (and fault-tolerant code in
Erlang's case).
Scala fixes a some issues of Erlang's design and improves on it in a few substantial areas (which can't be fixed in Erlang itself anymore due to backward compatibility).
It has better performance and better monitoring support.
Additionally, it offers better and more diverse tools to tackle concurrency than Clojure.
Haskell tries to make writing correct code easier.
While Scala does not enforce purity by default (there is an effect system plugin for that) it gets you a long way towards Haskell's “if it compiles it is most likely correct” guarantees.
Ruby and Python were made for ease and productivity
Apart from the “batteries included” approach (Scala prefers a minimal standard library instead¹) my experience is that it can easily match or beat Rupy's or Python's productivity.
¹ It also provides better tools to fetch additional dependencies than the languages mentioned above.
both Ruby and Clojure are great for DSLs
Well, people say that about Scala, too. I don't see the big deal about DSLs, I just try to design and implement the best API a library can possibly have and Scala gives me the right tools to make that happen.
Java and C are used nowadays for performance
Scala can match and beat Java's performance (looping seems to be faster than in Java, but I never understood why, optimization, specialization, macros, ...).
Java is relatively good for architecting huge software
systems
Scala's better OO and module support improves on that.
Now that's great, and Kotlin is all that, too.
Kotlin is a train-wreck. They promised a lot of things, but failed to deliver on pretty much everything. Sadly, those parts which were not just direct copies of Scala's design show the lack of experience in language design.
I think it is pretty ironic how their beloved talking points about “why not Scala?” has been reduced to almost nothing as they have continued to learn why Scala did things in a certain way. Just compare one of their first presentations with one of their latest ones.
They should really stop talking and start shipping if they want to be taken serious, because as a paying JetBrains customer I'm getting really tired of their vaporware and FUD.
Why the immutable data-structures, then? To make
concurrency better?
Partially. It makes reasoning about the program much easier in general and allows safe, structural sharing of data.
In that case, why is mutability just as easy?
Because Scala is not Haskell. Scala gives you tools to get your job done, it doesn't require you to adopt some ideology or religion.
Sometimes, a mutable algorithm/data structure fits a requirement exactly and Scala won't annoy you for picking it.
And what are implicits
Generally speaking, implicits are a generic way to guide the compiler towards closing a gap. What's such a gap?
It can make existing types implement new interfaces (think arrays, java.lang.String, ...), it wires up type class instances with methods which require them, it can make incompatible things compatible (e. g. types which come from different third-party Java libraries).
Have a look at how String is made to support Scala's collection API.
Have a look how the `to` method in Scala's collection library can work with arbitrary collection types (which don't even need to be known to the standard library).
They wouldn't be necessary in a perfect world, but Scala is pragmatic language and its designers acknowledge that we are not living in a perfect world. The cost/benefit ratio of implicits compared to things like extension methods is magnitudes better.
and these new cringe-inducing macros for?
They provide a general way to make APIs more safe and implementations more efficient. They can be used to report more specialized errors right at compile times, they can be used to make sure that your closures don't close over things you don't want, they can be used to implement LINQ to query databases while using the bog-standard collection API, they can be used to implement F#'s type providers. This can all be done with full type-checking and refactoring support from the IDE/compiler instead of having to resort to such terrible things as annotation processors, bytecode rewriting and Java agents.
They are a huge improvement over Java's approach and Oracle is now copying parts of it.
DSLs? Why would a high-performance, statically typed
language make it easy to write DSLs?
Why not? Just because it is a DSL, it doesn’t mean it has to such on the performance/safety front.
Why all the OOP, then?
Because OO is a good tool to solve some problems, just like FP is a tool to solve some other requirements.
Oh, it's to combine the too; in that case why do they
feel so strenuously glued together
I think you have to be more precise here. Even people coming from OCaml or F# concede that Scala has done an incredibly good job at combining OO and FP, so I'm happy to hear what issues you have found.
(classes vs. case classed,
Well, for some things it make sense to have the additional methods of a case class, for some use-cases it doesn't.
an entire collection package replicated twice, once for
the mutable case and once for the immutable).
Pick the best tool for your job. Some algorithms work best with immutable data-structures, some with mutable. Scala spells out explicitly which guarantees are made and people can safely rely on it.
Experience has shown that Java's approach had good intentions but just didn't work. Even the designers of Java agree with that these days. Scala has learned from those mistakes and doesn't repeat them (unlike Kotlin).
So the language offers a powerful compiler but absolutely
no guidance on how a program should be written.
That has not been my experience. There is some local immutable-OO-with-FP-with-typeclasses optimum and people regardless of where they come from are almost magically converging towards it.
If at least Scala had somehow provided all of these
features and stayed elegant,
I think it does.
but man, it would take you weeks just to understand how a
freaking Scala collection works, just because the
language designers wanted to be so clever and prove that
you could transform collections and still never require
casts.
Well, it's a bit more than that, right? Anyway, I think everyone in the Scala space is open towards a better solution, but frankly even after years no other language has come up with an approach which comes even close to collection API's ease of use.
It seems that at every turn Scala favors cleverness over
clarity
In my experience, readability and clarity are considered more important these days. Cleverness is deemed to be OK if it is used to improve the lives of people using that piece of API. It's just like mutability: It's ok as long as you keep it localized, confined and don't unnecessarily expose your users to it.
features over a cohesive philosophy
I think I disagree with that. Consistency is still one of the most important requirement and I don't have seen much features to make it in the last versions.
Anyway, Scala has much less features than Java 8, C#, F# and many other “competitors” in that space, so I think we are fine here.
Scala chooses, over and over, to try and address more
goals (most are really unimportant), and in the process
has lost the most important thing in a language:
coherence.
As mentioned, this has not been my experience, but I'd love to see an example.
Scala sees something nice in another language and
immediately adopts it.
No, absolutely not.
And I gotta say, writing a compiler that compiles code
that's both javascript and Haskell is an impressive feat
of engineering. But it comes at such high a price...
What is Scala for? If I'm hard-pressed to give an answer, I'd say, "better productivity than Java, in a statically typed language, with good performance". Now that's great, and Kotlin is all that, too.
Why the immutable data-structures, then? To make concurrency better? In that case, why is mutability just as easy? And what are implicits and these new cringe-inducing macros for? DSLs? Why would a high-performance, statically typed language make it easy to write DSLs? Is it to introduce developers to the wonderful high-level abstractions of FP? Why all the OOP, then? Oh, it's to combine the too; in that case why do they feel so strenuously glued together (classes vs. case classed, an entire collection package replicated twice, once for the mutable case and once for the immutable).
So the language offers a powerful compiler but absolutely no guidance on how a program should be written. If at least Scala had somehow provided all of these features and stayed elegant, but man, it would take you weeks just to understand how a freaking Scala collection works, just because the language designers wanted to be so clever and prove that you could transform collections and still never require casts. It seems that at every turn Scala favors cleverness over clarity, and features over a cohesive philosophy. Scala chooses, over and over, to try and address more goals (most are really unimportant), and in the process has lost the most important thing in a language: coherence.
Scala sees something nice in another language and immediately adopts it. And I gotta say, writing a compiler that compiles code that's both javascript and Haskell is an impressive feat of engineering. But it comes at such high a price...