Table of Contents for Programming Languages: a survey
Haskell
Because it is so well-liked, Haskell gets its own chapter.
See chapter on chapter on Haskell
Scala
Scala is a multiparadigm language, both OOP and functional.
Tours and tutorials:
Cons:
- big language
- slow compilation
- culture of punctuation-based DSLs can make readability hard
Best practices:
Tutorials and books:
Comparisons:
Features:
- higher-kinded types
- implicits
- " Scala is completely interoperable with Java (and with some qualifications also to C#). A Scala component can: • access all methods and fields of a Java component, • create instances of Java classes, • inherit from Java classes and implement Java interfaces, • be itself instantiated and called from a Java component. " -- [1]
- "Scala’s concepts subsume SML modules. More precisely, (generative) SML modules can be encoded inνObj,but notvice versa." -- [2]
- Abstract Types " Here is a type of “cells” using object-oriented abstraction. trait AbsCell? { type T val init: T private var value: T = init def get: T = value def set(x: T): Unit = { value = x } }
The AbsCell? class has an abstract type member T and an abstract value member init. Instances of that class can be created by implementing these abstract members with concrete definitions.
val cell = new AbsCell? { type T = Int; val init = 1 } cell.set(cell.get * 2)
The type of cell is AbsCell? { type T = Int }.
Path-dependent Types: You can also use AbsCell? without knowing the specific cell type:
def reset(c: AbsCell?): Unit = c.set(c.init);
Why does this work?
- c.init has type c.T
- The method c.set has type c.T => Unit.
- So the formal parameter type and the argument type coincide.
- c.T is an instance of a path-dependent type.
In general, such a type has the form x0...xn.t, where
- x0 is an immutable value
- x1, ..., xn are immutable fields, and
- t is a type member of xn " -- [3]
Some notes on Scala 3 features:
example of scala 3 'givens' which are (part of) the successor to scala implicits:
https://alvinalexander.com/source-code/scala-3-dotty-complete-givens-using-example/
so afaict these are just similar to Haskell typeclass instances. I guess what scala is really contributing is that i think these are lexically scoped, rather than globals like (i think) in Haskell.
Extensions:
Retrospectives:
Implementations:
Opinions:
- "Scala is the single best language I've ever used. And I don't even use all of it. I just use the subset of Scala that is Everything Java Should Have Been. It has lambdas and closures. It has just enough type inference. It has mutability control for slots. It has object orientation and case-classes/pattern-matching and type-classes via implicit parameters. Scala lets me figure out what language paradigm I need to Get Stuff Done. It's the Python of statically-typed languages, and it interoperates with a vast outside ecosystem to boot." -- [5]
- "I do want a functional language like Scala, because I believe that school represents a better design. That school of language design saves me the headache of null pointers; it helps me write unit tests with QuickCheck?; it allows me to define custom generic collections; it places emphasis on having a fast GC; it features monadic style to help with error handling." -- [6]
- [7]
- "...problem with all of these languages is that they are still obscure compared to everything else, with all that this entails: It's harder to find developers...Scala has some good parts, but is overdesigned and way too complex, in my opinion. Last I checked, performance was worse Java. It also runs on the JVM, which means its memory usage is inherently inefficient." -- [8]
- "Scala has always seemed like an abomination to me, but I haven't used it enough." -- [9]
- http://grundlefleck.github.io/2013/06/23/using-scala-will-make-you-less-productive.html
- "Scala's the only one of these three languages with any adoption right now. Groovy is virtually only used in its original dynamic mode from 2003 for things like scripting and Gradle build files, and very few people use the @CompileStatic? mode introduced in 2012. Kotlin 1.0 has just been released, was subjected to stringent QA, and I expect JetBrains? to use it more and more in its own products like IntelliJ?, so it's a good bet it will become more popular with developers. So I'd say use Scala and Kotlin if you need static typing. Clojure, though it doesn't have static typing, has other features like syntactic macros for terseness, default immutability, and concurrency that would recommend it in many situations." [10]
- https://news.ycombinator.com/item?id=11678751 : "
- "While the fusion OOP + FP fusion is interesting I have grown wary of kitchen sink languages. There are so many ways people write Scala. " [11]
- Lends itself to DSLs (some people think this is good, others thing it is bad [12])
- "I remember when I first saw the potential issues of scaling Scala at Gravity back in 2009/10ish. It was close to the end of the day when we had a major issue reported in production that was affecting our large customers. Several of us started investigating and were able to track the source of the issue. The only problem was we had no idea what the code was doing at first. We came across a strange symbol we hadn’t seen in our projects before. The spaceship operator <
- slow build times
- "Scala has had big issues with the size of it's library that still haven't been resolved" [14]
- "I worked on a commercial project that used Scala. Never again. Compiles were slow, IDE support was terrible, everyone had their own subset they used. I'm sure it's improved since 2010. " [15]
- "The language and even the basic libraries are incredibly complex. Here's an example, a signature for List.map: final def map[B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom?[List[A], B, That]): That" [16] (other comments in that subthread explain what that signature means)
- vs Kotlin: https://elizarov.medium.com/why-im-not-enthusiastic-about-java-10-b2d789b6d42a
- Because all the other languages mentioned are better only from very specific perspectives. Scala's strength is precisely that it's a mutt: Want to write imperative code? Sure. Functional? No problem. How about a type system that far more featureful than Go? That works too.
Scala gets a bad rap precisely because people are big fans of their own way of writing code, call it better, and think that anyone that wants something else is deluded. The Scala way is to say 'sure, you can do that too, to hell with purity'. I'd rather have power over purity any day.
reply
duaneb 36 minutes ago
> Scala's strength is precisely that it's a mutt: Want to write imperative code? Sure. Functional? No problem. How about a type system that far more featureful than Go? That works too.
This also essentially describes C++. This is also why both languages can be so terrible to use: every library has its own dialect.
reply
the_af 20 hours ago
Note: I use Scala in my day job. I consider it better than Java, but worse than other languages. I definitely agree that all languages accumulate compromises and inelegant hacks as they evolve. It's unavoidable.
That said, in my opinion Scala's blunders are many. You can find out about many of them from Paul Philips, ex committer of Scala, but if he sounds too bitter to you (he does to me; at this point he sounds like there is bad blood between him and Odersky), here are some of mine:
- Null. Null will come back to bite you in Scala code, whenever you call Java libraries, and the occasional Scala library that didn't get the memo. Sure, you can wrap every suspect value with Option(...), but why should you do this?
- Type inference is not as powerful as in a language with a cleaner type system such as Haskell. I'm told this is because Scala tries to be both OOP (inheritance) and FP at the same time. Here is a clear case of Scala's attempt at being a "jack of all trades" resulting in it being inferior than the sum of its parts.
- Type signatures in Scala collections and core types are extremely hard to read. You do not need to read them, but if you try, you are in for a world of hurt. This in itself is not a mortal sin, but of course if you're willing to forgive Scala this much complexity, surely you're willing to forgive other languages as well?
- Tooling is bad. It's getting better, but it's still bad. SBT is painful to use. As for IDEs, IntelliJ? is now the recommended choice; I've tried both Scala IDE and IntelliJ?, and they both suck. Slow, spurious compilation errors, uncomfortable to use.
- And finally, telling bit of personal experience: I do NOT use Haskell professionally, yet whenever I want to try a quick idea and see if it typechecks, I find it easier to open ghci (the Haskell REPL) and try my idea than do the same with the Scala REPL. What does this say about Scala?
reply
airless_bar 20 hours ago
> all languages accumulate compromises and inelegant hacks as they evolve. It's unavoidable.
Scala devs deprecate and remove things that haven't worked out well. They have an established track record of making these migrations easier with each release.
> Null
Upcoming versions will make references non-nullable by default. If you want things to be nullable, you will have to opt-in explicitly with T
> - Type inference
Type inference is not a huge priority, because people think that it's a good thing that declarations require type annotations (just like it's recommended in Haskell, too). One of the last pain-points, higher-kinded unification of type constructors, has been fixed recently which will make type inference "just work" in exactly those cases where the lack of type inference was most annoying.
> - Tooling
I think tooling is pretty amazing. Sure, Java has still some advantages in some places. But the tooling is superior to almost all other languages out there. SBT is amazing. IDE support is getting vastly better, not only have Eclipse and IntelliJ? improved vastly, but also IDE support for Emacs, Vim, Sublime, etc. is coming along at a rapid rate, and it's just amazing to use. There are so many tools in the Scala ecosystem which just don't exist in this combination anywhere else.
airless_bar 19 hours ago
Alright. Sorry.
Regarding your question about nulls and Java:
I think that there is not much Scala can do here. All existing evidence from other languages that tried this shows that there is a large semantic gap between "nullable values" and "values of unknown nullability".
As Scala is much more independent of Java it is a much smaller issue, but improvements with Java interop require action from Java library authors first.
The approach of supplying external nullability meta data has largely been a failure, because
a) authors are not aware of the stated, external constraints, so they could break these assumptions in future releases without even knowing
b) it's really really hard to retrofit nullability guarantees into libraries which have been designed without this requirement in mind
c) the existing ecosystem is not very amenable to these guarantees, as nullability metadata would be largely limited to final classes and members, because everything else could be subclasses or overridden in third-party code, breaking these assumptions
As soon as Java library authors themselves start using @Nullable/@NonNullable? annotations everywhere, there is a good opportunity of reading these annotations and typing the values accordingly, but without it, benefits are very slim.
The planned changes are valuable for dealing with nullable types, but as mentioned "unknown nullability" needs a different solution, and I think it's currently not worth adding something to the languages as long as there is still hope for widespread adoption of nullability annotations.
reply
bad_user 17 hours ago
- I've never experienced null problems in Scala. There's theory and there's practice. In practice if a NPE does happen, you treat it as a bug and wrap it. I don't experience problems, because Scala libraries are well behaved and for Java libraries I read the docs.
- Being a "jack of all trades" means Scala has the superior module system. In Scala you can have abstract modules, the way you have in Ocaml. In Scala type-class instances are lexically scoped, whereas in Haskell they are global. Haskell's type-classes are anti-modular, which is why there are people avoiding type-classes. A big part of what makes Scala so good is OOP. Haskell needs extensions to achieve similar functionality in a half-baked way and modularity is the main complaint of people coming to Haskell from Ocaml.
Btw, if you ask a C++ developer to describe OOP, he'll say it's the ability of having structs with a VTable attached. Most people think OOP is about state. That's not true, OOP is about single (or multi) dispatch and subtyping (having a vtable), hence it's not at odds with FP, unless you want it to be ;-)
- SBT is amongst the best build tools ever available. I could rant all day about the clusterfuck of Javascript (npm, Bower, Grunt, Gulp, Brunch.io, etc.) or Python (easy_install, setuptools, virtualenv) or .NET (MSBuild, Nuget, dotnet) or Haskell (cabal). For all its quirks, SBT is by far the sanest dependency and build management tool I've worked with. In fact, amongst the best reasons for preferring Scala.js is being able to work with SBT and avoid Javascript's clusterfuck completely.
- I've been working with IntelliJ? IDEA with the Scala plugin for the last 3 years. I've had some problems with it, but all minor and it's amongst the best IDEs available, giving you everything you expect out of an IDE. Other platforms either don't have an IDE (Haskell), or require extra commercial plugins to behave like an actual IDE (Visual Studio).
And let me give an example: in IntelliJ? IDEA I can click on any identifier in any third-party dependency and it automatically downloads and shows me the source code and I can set breakpoints and debug any third-party dependencies that way. Such a simple thing, yet it's a tough act to beat. Try it out in Visual Studio sometimes.
reply
asragab 16 hours ago
What languages would you say have definitely better tooling: I'd say for sure the .NET languages, C++, Java, and Javascript but I'd put Scala just at a level below that, no? The tooling stories for Go, Rust, Haskell I don't think are as strong (yet), but that's definitely going to change though.
reply
airless_bar 16 hours ago
Not parent, but I would reduce it down to
- C# with VisualStudio? + JetBrains? addon
- Java with IntelliJ?
Why not the others you mentioned?
- IDE support for F# is not very good.
- VB is too dynamically typed to be reliable.
- C++ IDEs seem to be constantly fighting with constructs that manage to break the IDE's understanding of the code. It's gotten better with LLVM, but even VisualStudio? is far away from providing a reliable experience.
- JavaScript? is dynamically typed, so IDE support is not reliable.
reply
pjmlp 11 hours ago
- VB.NET support is at the same level as C#
- F# does lack some Microsoft love, but Visual F# Power Tools does improve the experience a lot
- Netbeans and Visual Studio 2015 are quite good in JavaScript? support, specially on code where JsDoc? comments are available
reply
"
- "The main problem of Scala is that it brings in the whole JVM. That's awesome for certain kinds of apps, but not so great for other things like small tools. I have high hopes on scala-native, though!" [17]
- http://matt.might.net/articles/best-programming-languages/#scala
- "You want a statically typed functional (but not pure) language with sum types, immutable data structures, good performance, editor/IDE support, a broad library ecosystem, multithreading, a C-like syntax (I assume, since you're using ReasonML?), and a nice compile-to-Javascript experience to run in the browser. I don't want to sound too much like a fanboy, but all this really sounds like Scala. You want Scala." -- lihaoyi
- "...Scala has a similar thing for this where sometimes Eta expansion happens and sometimes it doesn't, and you just need to know where you can use sugar." -- [18]
- "...I miss relatively basic things like c-style for loop (so I can use a for loop on linked lists rather than a while), or things like a list that can have more than Int.MaxValue? numbers. " [19]
- "Always struck me as a functional language that was more complicated than it had to be because it needed to interoperate with the existing Java ecosystem, run on the JVM, handle Java exceptions, etc." -- [20]
Opinioned comparisons:
- "I like Scala too. But it lacks some things that Go has, and help me in a few cases: no static binaries. No control over memory alignment. No dead easy FFI to C. No dead simple syntax I can understand in a weekend." -- [21]
- https://www.reddit.com/r/haskell/comments/3h7fqr/what_are_haskellers_critiques_of_scala/
- "Being a "jack of all trades" means Scala has the superior module system. In Scala you can have abstract modules, the way you have in Ocaml. In Scala type-class instances are lexically scoped, whereas in Haskell they are global. Haskell's type-classes are anti-modular, which is why there are people avoiding type-classes. A big part of what makes Scala so good is OOP. Haskell needs extensions to achieve similar functionality in a half-baked way and modularity is the main complaint of people coming to Haskell from Ocaml." [22]
- https://movio.co/blog/migrate-Scala-to-Go/
- http://jimplush.com/talk/2015/12/19/moving-a-team-from-scala-to-golang/
- "Do I miss immutable types and some of the great features of Scala? Sure do, but I think the maintainability side of the story is too great to overlook with Go. We’ve seen faster ship times, better stability and better test coverage being written." -- [23]
- "At it's core Scala is very simple & the syntax is very regular, far more than Go or Java and a lot less complex than C++." [24]
- "I liked it more than Java (7), though I find the syntax aesthetically offensive (and I realize that's subjective). Ada (I worked in an Ada shop for 3 years before moving to the JVM) managed to have a robust type system without introducing the sort of syntax wtf-ness that Scala seems to need. I actually recommended against using Scala at a later job simply because I thought the learning curve would be beyond most of the people I was working with (I didn't phrase it quite like that when mgmt asked me for my opinion, of course). Learning to write idiomatic Scala takes time. " [25]
- http://thume.ca/2019/04/29/comparing-compilers-in-rust-haskell-c-and-python/
Scala examples
" To give a feel for the language, here’s a Scala implementation ofnatural numbers that does not resort to a primitive number type.
trait Nat { def isZero: Boolean; def pred: Nat; def succ: Nat = new Succ(this); def + (x: Nat): Nat = if (x.isZero) this else succ + x.pred; def - (x: Nat): Nat = if (x.isZero) this else pred - x.pred; }
class Succ(n: Nat) extends Nat { def isZero: Boolean = false; def pred: Nat = n }
object Zero extends Nat { def isZero: Boolean = true; def pred: Nat = throw new Error("Zero.pred"); } " -- [26]
(S)ML
Pros:
Tutorials and books:
Comparisons and opinions:
- http://thebreakfastpost.com/2015/04/22/four-mls-and-a-python/ vs other MLs, Python
- "...all the extant MLs fall short in one way or another. A modern SML with none of the syntactic cruft of OCaml; the lazy evaluation of Haskell and its non-existent module system; the nutured nature of F# ... that would be ML joy, maybe Rosenberg's 1ML will make that a reality." -- https://news.ycombinator.com/item?id=10210679
- vs Haskell: "From one view, ML is the worse language, but from other views it would be Haskell. Suppose you require a fully formal specification which has been verified in a mechanized way. You have that for Standard ML in Twelf and Haskell has nothing sort of that. If you look at the concept of being a purely functional language however, it is the opposite with Standard ML being the "worse" animal. Module system: Then SML got it right and Haskell got it Wrong. Laziness/Strictness: This is a duality. There are advantages and disadvantages to both approaches so there is no worse/right choice IMO. If you look at the recent stuff on polarity in proof theory it becomes clear that when you latch onto a specific evaluation order, you make some things simple and other things hard." [27]
- What's Wrong with C++ Templates? compares C++ templates to Java interfaces and ML modules
- http://matt.might.net/articles/best-programming-languages/#ml
- https://blog.plover.com/prog/haskell/sml-defects.html
Wishes:
Implementations:
Links:
Variants:
Retrospectives:
Ocaml
Tours and tutorials:
Features:
Library recommendations:
Retrospectives:
Updates:
Opinions:
- "general-purpose language...good predictable performance...strong type system...the last thing, which I think is more unique to OCaml or at least more unique to the MLs, is that OCaml takes modularity very seriously" -- Leo White
- "One of the main reason I got into Ocaml (coming from C++) was that it had bytecode compilation (and obviously a bytecode interpreter) next to the native one. This is really fast (5-7 times faster last time I measured) and perfect during development, when you don't really care about performance. " -- [29]
- "I wanted to use OCaml several types but the lack of parallelism and the GIL have put me off. Still waiting for Multicore OCaml." [30]
- "Its compiler is actually very good (when it comes to emitting correct code, being fast, and having few compiler bugs). What is lacking is indeed a few “modern” things: no standard deriving/serde (where rust clearly shines) bigints are not the default (zarith is neat but it’s not as seamless as int) the portability/static binary story is lacking. It’s really sad, because OCaml with some of Go’s tooling qualities would be incredible. " -- [31]
- " Yeah, OCaml is frustratingly close, but I also have a few gripes with its inner workings: objects are redundant polymorphic equality/hash/comparison is awkward, which is a sign of a deeper ad-hoc polymorphism issue compilation model with a shared global namespace and without explicit DAG of dependencies is pretty horrible (ocamldep is one of the grossest hacks in my book) no mature multicore support " -- [32]
- " ocaml objects aren’t any more redundant than any feature in any language that has more than one way to do things. they may not be much used due to cultural/ecosystem choices, but every now and then they are the most ergonomic solution to what i’m trying to do. the namespace issues are indeed a pain though :( after getting a day job working in python i have been dissatisfied with namespacing in both ruby and ocaml, which are otherwise two of my favourite languages. " -- [33]
Ocaml Opinions:
- Q: "why (does) so much symbolic evaluation stuff gets done in OCaml? What does OCaml do that makes it so well suited for this problem domain?"
- A: "...pattern matching is really nice for this kind of thing. Of all of the functional programming languages, OCaml has probably the most sophisticated pattern matching engine around (and we basically copied it into Rust, incidentally), supporting or-patterns, multiple bindings, guards, and so forth. Pattern matching lets you essentially match on the shape of subtrees of arbitrary data structures with complex predicates. If you're familiar with old-school compiler construction, this is like having a souped-up BURG built into the language. For example, pattern matching lets you say things like "if I have Load(Var, Add(Var, Constant)) where constant is a small power of two, fold it into the x86 indexed addressing mode" in one line...." -- https://news.ycombinator.com/item?id=9701011
- A: "...pattern matching, ADTs and higher-order functions are ideal for symbolic manipulation. Nowadays many languages have that (Scala, Rust, F#, Haskell), but Ocaml is old and was probably the first language that offered these features and had a really fast, rock solid compiler producing really fast, high-quality code (since the 1990s)." -- https://news.ycombinator.com/item?id=9702675
- A: "Symbolic reasoning involves a lot of term-matching and term-rewriting. These tasks are best accomplished in programming languages that have first-class support for recursive terms (aka. algebraic data types). Popular candidates these days are OCaml, Haskell, Scala." -- https://news.ycombinator.com/item?id=9700976
- "Here are some examples of what is possible with symbolic manipulation in OCaml, although I would recommend learning a bit of OCaml syntax and concepts from a book first (such as Real World OCaml):
- A short example of implementing regular expression matching using Antimirov's partial derivatives that illustrates symbolic manipulation: http://semantic-domain.blogspot.ro/2013/11/antimirov-derivatives-for-regular.html . A step-by-step explanation of a DSL optimizer that doesn't use too many advanced notions of OCaml: http://okmij.org/ftp/tagless-final/course/optimizations.html . A nice example of symbolic manipulation is this counter-example generator for regular expression equivalence: http://perso.ens-lyon.fr/damien.pous/symbolickat/ " -- https://news.ycombinator.com/item?id=9701756
- "I'd characterize OCaml's tools as a mixture of best-of-breed (Merlin, OPAM) and oh-my-god (build tools, debugger). The language itself, if you avert your eyes from the standard library, is pretty damn good though." -- * "One of the biggest problems now is the [https://github.com/ocaml/opam/issues/246 lack of the Windows support for Opam. I hope that will be solved in the near future. Because currently Microsoft trying to take the niche with their F#." -- [34]
- "OCaml is super-practical for writing simple command line tools. It interfaces easily with C and compiles to binaries with no dependencies. See: all the tools written in OCaml here: https://github.com/libguestfs/libguestfs " -- [35]
- "...problem with all of these languages is that they are still obscure compared to everything else, with all that this entails: It's harder to find developers...OCaml looks to me like the most promising functional language with the fewest warts, the most pragmatic approach to real-world apps, and possibly the best performance. But it's not a simple language, with a learning curve that's similar to Haskell. I also have to say that like Erlang, the toolset and syntax occasionally feels antiquated (for example, there's no excuse not to provide a modern readline-enabled REPL). OCaml still is not good at concurrency." -- [36]
- "Ocaml is also a great language but it had problems with poor standard libraries and concurrency support." -- [37]
- OCaml for the Masses: Why the next language you learn should be functional
- http://www.podval.org/~sds/ocaml-sucks.html
- "...I have been absolutely blown away by the amount of power this language provides. It strikes a nice balance between high-level expressiveness, while not sacrificing on performance. I feel like OCaml is one of the programming world's best kept secret - if it had better tooling and better marketing, it could have taken over the world. I'm cautiously optimistic about ReasonML? for this reason." [38]
- " Version incompatibility is a big problem for OCaml. Every time I try to use it seriously, the recommended tools never seem to work together on anything but the latest version. It's like Rust, but without the "young language" excuse. My impression is that INRIA is too eager to add features and tweak the language. Next, everything builds so slowly, and just trying to set up Core, utop, and ocp_indent is a trial in patience, watching the same dep build again and again, confusion about OPAM switches.... nope nope. OCaml/OPAMs's got a distribution problem. They've pushed the complexity off to the end user and the experience is terrible. Jane Street planting their flag on the language and encouraging massive dependencies like Core, or shit like "corebuild" is even worse. I would never depend on anything OCaml-based on it unless it could be installed by my OS' package manager (Arch/AUR doesn't count, because it builds). That rules out most popular OCaml tooling, and ruins the development experience. I'd prefer OCaml to Haskell, I find it more practical, but I feel much better depending on Haskell-based software, which generally "just works." As much as they're a wart, Haskell syntax extensions are a real benefit. You can build new fancy Haskell software with older GHC versions." [39]
- https://news.ycombinator.com/item?id=7769404
- "there is not much manpower behind it. All those Reason XYZ attempts to provide javascript syntax over it don't seem to have gotten traction. Tooling is pretty good considering how obscure language is. They might need a modern interface to toolchain, and an optimizing compiler seems to be being worked on. La k of multicore is often cited as a drawback but it is being worked on, and Python doesn't do multicore either, I don't think multicore matters to 90% of people doing webdev." -- [40]
- "Keiichi once told that one of the reasons they could grow Ucc so rapidly was that they wrote Ucc by OCaml. OCaml allows you to manipulate tree structure so easily without any pointer bugs." -- [41]