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:
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)
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)
}
}
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
}
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) |
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 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 |
Issues | Haskell | Scala* | Go |
---|---|---|---|
Known | 942 | 4772 | 1216 |
Critical | 5 | 157 | N/A |
Major | 42 | 443 | N/A |
FFI | C, JS | Java, C | C |
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!
$ 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
------------------------------------------------------------------------
$ 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
-----------------------------------------------------------------------
$ 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
-------------------------------------------------------------------------
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.↩