Presenting - Comparing Haskell, Scala, and Go

Update Aug. 29, 2014, 4:30p CST: Update Scala sample to compile.

Update Aug. 29, 2014, 12:24p CST: I’ve provided more accurate representations of the complexity of each language. Furthermore, I’ve added a package index for go. Thanks for all your feedback!

Link: pdf

For work and for my own sake, I decided to take a closer look at a few languages on the periphery of what I do. I wanted to be able to explain as objectively as possible what each of these languages has to offer. Towards that end, I decided to learn enough Scala and Go to understand how they work (at a high level).

Due to time constraints (and head space constraints), I’ve limited the content in this presentation. In particular, I don’t dive into:

I also didn’t get a chance to jump into some other exciting languages:

As you all may know, I specialize in Haskell. Be forewarned that I have my biases. I disclaim the particulars of this at the very end of the slides linked above. Without further ado, here’s some tables:

Syntax: at a Glance

Haskell

factorial :: Integral a => a -> a
factorial n
  | n < 2 = 1
  | otherwise = n * factorial (n - 1)

data Tree a =
    Empty
  | Branch a (Tree a) (Tree a) deriving (Show, Eq)

insert :: Ord a => Tree a -> a -> Tree a
insert Empty x = Branch x Empty Empty
insert (Branch v l r) x
  | x <= v    = Branch v (insert l x) r
  | otherwise = Branch v l (insert r x)

Scala

sealed trait Tree[A]
case class Empty[A]() extends Tree[A]
case class Branch[A](v: A, l: Tree[A], r: Tree[A]) extends Tree[A]

object samples {
  def insert[A <% Ordered[A]](t: Tree[A], x: A): Tree[A] = t match {
    case Empty() => Branch(x, Empty(), Empty())
    case Branch(v, l, r) =>
      if (x <= v) Branch(v, insert(l, x), r)
      else        Branch(v, l, insert(r, x))
  }
  def factorial(n: Int): Int = {
    if (n < 2) 1 else n * factorial (n - 1)
  }
}

Go

func factorial(n int) int {
	if n < 2 {
		return 1
	}
	return n * factorial(n - 1)
}

type Tree struct {
	l, r *Tree
	v interface{}  // not type-safe; sort of like (void *)
}

func insert(t Tree, x interface{}) Tree {
  // not-even-going-to-try.jpg
}

Overview: at a Glance

Summary Haskell Scala Go
Appeared 1990 2004 2009
Latest Release Date July 2014 July 2014 August 2014
Platform x86, ARM* JVM x86
Paradigm Functional, Imperative OO, Functional OO, Imperative
REPL Yes Yes No
LOC Main1 394539 (Haskell) 268572 (Scala) 432018 (Go)
LOC Other 45760 (C) 29919 (Java) 151908 (C)

Library Ecosystem: At a Glance

Packages Haskell Scala Go
Index Hackage Maven Go-Search
Count >6000 >80000 (+Java) >50000
Manager cabal sbt gopm (exp.)
FFI C, JS Java, C C

Type Systems: At a Glance

Type System Haskell Scala Go
Analysis Time Static Static Static
Immutable Default Yes (all) No No
1st-Class Functions Yes Yes No
Type Inference Yes Yes* Poor
Evaluation Model Lazy Strict Strict
Modules Yes (weak) Yes (strong) Yes (strong)
Implicit Casts No Yes No*
Generics Yes Yes No
Higher Kinds Yes Yes No
Nullable Values No Yes Yes
Strong Type Alias newtype case class No
Sum Types Yes Yes No
Product Types Yes Yes No
Recursive Types Yes Yes No
Pattern Matching Yes Yes No
Effect Tracking Yes Possible* No
Overloading Typeclass Implicits No
Records Yes Yes Yes
Subtyping No* Yes Yes
Dependent Types No* No* No

Tool Chain Issues: At a Glance

Issues Haskell Scala* Go
Known 942 4772 1216
Critical 5 157 N/A
Major 42 443 N/A
FFI C, JS Java, C C

Future Work

I’d love to expand this work to include other languages. It’d be lovely to make a website out of this, something where you could, “At a Glance”, investigate aspects of a language that are of interest to you. Sortable table views, single-page application, colors for emphasis, all that nifty JS magic.

Thanks for reading!


Haskell Lines of Code

$ git log --pretty=oneline | head -n 3
9491fea2e8c034ed1ed4b2d8bb916a56b41ab796 Typos in comments
fa9dd0679ec6b75a22213433e860ccb39e89b975 Do not say we cannot when we clearly can
5da580beacb0da1f7bf8e300e074e5cad88b8bbc Performance improvement of the compiler itself

$ du -sh compiler/ rts/ libraries/ testsuite/
11M	compiler/
2.5M	rts/
28M	libraries/
40M	testsuite/

$ cloc compiler/ rts/ libraries/ testsuite/
   11485 text files.
   10619 unique files.
    4684 files ignored.

------------------------------------------------------------------------
Language                     files          blank        comment    code
------------------------------------------------------------------------
Haskell                       6076         107964         150094  394539
C                              198           8613          11912   45760
C/C++ Header                   136           1953           2584    5597
Bourne Shell                    18            308            526    3994
Pascal                           2            977            618    3757
make                           134            858            583    3215
Python                           6            581            406    1897
yacc                             1            209             10    1147
m4                              15            174             30     911
HTML                             3             77              1     793
YAML                            16             68             30     529
Lua                              2             79             19     440
Assembly                         5             34             31     195
XML                              1             35              1     154
Perl                             3             18              6      87
D                                2             16             39      59
Teamcenter def                   3             19              0      57
CSS                              2             10              0      44
Objective C                      1             11              3      21
Objective C++                    1             11              3      21
C++                              1              1              0       2
------------------------------------------------------------------------
SUM:                          6626         122016         166896  463219
------------------------------------------------------------------------

Scala Lines of Code

$ git log --pretty=oneline | head -n 3
7693cecc8b3cf56984a041bb2d7979e2a040314a Merge pull request #3949 from lrytz/t8627
9276a1205f74fdec74206209712831913e93f359 SI-8627 make Stream.filterNot non-eager
b9048bb8a7d91e032eb57afa3ec12d3987980fe9 Merge pull request #3905 from gourlaysama/wip/t5691-2

$ du -sh src/ test/
17M	src/
42M	test/

$ cloc src/ test/
    9932 text files.
    8960 unique files.
    3151 files ignored.

-----------------------------------------------------------------------
Language                      files          blank     comment     code
-----------------------------------------------------------------------
Scala                          6134          55559       88903   268572
Java                            402           4433       24121    29919
Javascript                       11            705        1502     4794
CSS                               5            246         103     1121
Python                            5            169         379      666
XML                              21              3          13      588
Bourne Again Shell                5             55          91      277
HTML                              3             19          13      193
DOS Batch                         7             53          40      139
Bourne Shell                      7             40          36      121
Ant                               1              5           2       26
C/C++ Header                      1              2           7       12
C                                 1              2           0        6
-----------------------------------------------------------------------
SUM:                           6603          61291      115210   306434
-----------------------------------------------------------------------

Golang Lines of Code

$ hg log --template "{rev} {desc|firstline}\n" | head -n 3
20958 runtime: implement 64 bit division in Go
20957 text/template: add back pointer to Nodes for better error generation
20956 runtime: clean up GC code

$ du -sh src/ test/
30M	src/
8.7M	test/

$ cloc src/ test/
    3785 text files.
    3691 unique files.
     290 files ignored.

-------------------------------------------------------------------------
Language                      files          blank        comment    code
-------------------------------------------------------------------------
Go                             2672          52690          66957  432018
C                               387          21011          22264  151908
Assembly                        229           3672           4154   23192
C/C++ Header                    125           1971           2621   16289
yacc                              6            406            388    4971
Bourne Again Shell               10            190            220    1332
Perl                             12            180            172    1105
Bourne Shell                      9             96            296     682
DOS Batch                         6             74              1     320
Python                            1            115             82     281
awk                               2             14             35     121
make                             10             33             29      70
HTML                              1              0              0       1
CSS                               1              0              0       1
-------------------------------------------------------------------------
SUM:                           3471          80452          97219  632291
-------------------------------------------------------------------------

  1. Lines of code determined by the sum of lines involved in crafting each language’s compiler, runtime system, and packaged standard library. Commands and output provided.