I have never tried Haskell, so I cannot really hold any truly fair opinion there, but I find Odersky's "values" or approach to programming language design much more in line with my own. Scala 3 seems like a very well designed language (pragmatic, expressive, conceptually solid).
Odersky's "values" primarily appear to be whatever will appease the masses, which is why Scala started with curly braces and OOP. So much of his intellectual capital has been spent on trying to combine objects, subtyping and FP, that I can't help but feel it could have been better spent elsewhere. Folks are moving on from OOP. Scala is in danger of building what people once wanted, but don't want any more. IMHO there are better ways of bringing first-class modules to FP (e.g. see the 1ML paper).
I would agree that Odersky wants Scala to be popular and wants to accommodate even programming novices. For example Python (and a little bit Haskell and F#) proved significant whitespace to be popular, so Scala 3 now has it. In times of XML's popularity, on Wadler's suggestion, XML literals were added to Scala. Today AFAIK using XML literals is now popular in many frontend/browser frameworks/languages (although XML literals have been dropped from Scala 3).
But that doesn't mean that Scala design is unprincipled. On the contrary, there are 3 pillars that make Scala what it is, all working together in a unified and coherent manner:
* Modularity (objects, interfaces, etc, sometimes called OOP)
* Functional programming (ADTs, pattern matching, preferring immutability, higher order functions, ...)
* Meta-programming (Scala 3 features powerful Macro system, AFAIK inspired from MetaOCaml)
> Folks are moving on from OOP. Scala is in danger of building what people once wanted, but don't want any more.
More and more languages are becoming more and more like Scala:
* Rich type system instead of unityped
* type inference vs having to manually annotate everything
* higher order functions instead of not having them
* preferring immutability instead of mutation everywhere
* ADTs, pattern matching instead of "OOP style" modelling
* module system (sometimes also called OOP) instead of non-modularity
* strict instead of lazy
* ...
It's interesting to see such convergence. New languages are more like Scala now than before. And already existing languages, even though starting are more different, are getting closer to Scala by adding more features. That is to say, Scala is not magical or prophetical, not even original (most, if not all, individual feature was done before in other language), but it's just ahead of the others with combining these features.
https://news.ycombinator.com/item?id=26101435
https://old.reddit.com/r/scala/comments/lerd3t/from_first_pr...
> 1ML paper
I will definitely check it out. Thanks for the suggestion. A quick research suggest that 1ML can't model objects and classes (in the OOP lingo), as per slide 6 in https://www.slideshare.net/Odersky/from-dot-to-dotty https://skillsmatter.com/skillscasts/8866-from-dot-to-dotty
In the meantime, I will continue enjoying Scala that allows me to do Pure FP in a modular fashion while getting paid for it because of its huge (relatively speaking) job market :)
But what does he mean by "Objects" and "Classes"? Everything good about objects that a pure functional programmer would want is captured by first-class modules. The internal mutable state and subtyping/inheritance relationships are much less useful. In fact, even OOP thought leaders are advising not to use them.
> In the meantime, I will continue enjoying Scala that allows me to do Pure FP in a modular fashion while getting paid for it because of its huge (relatively speaking) job market :)
That's a very good reason to use Scala! But please do take a good look at Haskell too, if only just for interest. Many leading Scala programmers ended up moving to Haskell, in order to get deeper into FP.
Haskell allows this, you just have to actually demonstrate that the mutation is local:
statefulSum :: [Int] -> Int
statefulSum xs = runST $ do
n <- newSTRef 0
traverse (\x -> modifySTRef n (\y -> y + x)) xs
readSTRef nBut Odersky's point is that (at least in Scala) it is even simpler (and thus should be preferred) to do it with raw (but still local!) mutation.