It’s only half an hour till ICFPC 2015 and your team suddenly decides to switch to Scala for this year? Don’t panic — you’ve got just enough time to bring yourself up to speed.
Let’s kick off with…
Random facts about Scala
Predef is Scala’s analog of Prelude.
Scala has subtyping.
The language doesn’t separate pure and impure code on the type level.
Functions can’t be declared on the top level; everything should reside within classes and objects.
Operators are actually methods;
a + btranslates into
a.+(b). Operators that end in colon are special;
a :: btranslates into
One of the design goals of Scala is seamless Java interop; half of your “why” questions can be answered with “because Java” ☺
There’s a whole set of integer types (just like in Java):
Haskell: Int8 Int16 Int32 Int64 -- from Data.Int Scala: Byte Short Int Long
Floating-point types are the same two,
Double; no surprise there.
String, are spelled the same, but Scala’s
Char is actually a 16-bit unsigned Unicode character, and thus
String is in UTF-16.
Boolean type is spelled a bit differently and, most importantly, its values are all lowercase:
Haskell: Bool -- True and False Scala: Boolean // true and false
() (the type) is spelled
Unit (but the value is still
String, all of the above are value types. They have a nice property: they can’t be
null. Reference types, on the other hand, can. This distinction is mirrored in the class hierarchy of Scala: value types are subtypes of
AnyVal, while reference types are subtypes of
AnyRef. Finally, all the types are subtypes of
Nothing is a subtype of every other type.
Null is a type inhabited only by
Algebraic data types
Being an object-oriented language, Scala uses class hierarchies to build ADTs.
sealed keyword — that makes
Tree a closed ADT, i.e. one that can’t be extended with new value constructors (just like in Haskell). You can omit the keyword if you need an open ADT, of course.
case keyword before the class definition enables the following:
- constructor function is automatically defined: instead of
new Node(…), you can simply write
hashCodeare automatically implemented. Their values depend on the structure of the class (i.e. the arguments you pass into the constructor);
- accessor methods are automatically defined (they’re methods, so no risk of name collisions here);
- we can pattern-match on
caseclasses (more on that in a minute).
Leaf could’ve been defined as another
class, but since it has no constructor parameters, all the instances will be the same. Thus an object definition which makes
Leaf a singleton.
Return type annotations are optional, argument type annotations aren’t:
Unlike Haskell, Scala functions aren’t curried by default — it’s your responsibility:
You can put single
_ after the function or method to get partially applied function:
But you can also use
_ as a placeholder for some of the arguments:
Polymorphism and type constraints
Scala doesn’t rely on hierarchy of typeclasses to overload common functions and operators — here, you can just implement method
+ and be done with it. Thus, type constraints are used only to limit subtyping.
For example, if we have class
C2 that extends class
C1 which, in turn, extends
AnyVal, the following code will work on both
C2, but not on
Conversely, the following will work on
Any, which is a superclass of
AnyVal), but not on
(These margins are too narrow to contain meaningful examples, sorry.)
Traits are like Haskell’s typeclasses — they define an interface that a type should implement.
Okay, so if traits and type constraints are not used to write contracts, what is? Meet implicit parameters.
Another thing that you never had to deal with in Haskell is co- and contravariance (because Haskell doesn’t have subtyping). If you want your trees to be covariant, just add plus before the type variable:
To make it contravariant, use
Lists are eager. All the usual functions on lists —
map etc. — are methods in Scala.
forM_ is spelled
foldLeft in Scala (also spelled
/:) is the same as
flip $ foldl' in Haskell, i.e. it takes the base value as the first argument and the function as the second. There’s also
reduceLeft which is like
foldl1, only strict;
:\ (arguments are flipped, too); and
Streams are effectively lazy lists.
…are imperative counterparts of streams.
Iterator[+A] is a trait specifying two methods,
hasNext: Boolean and
next: A. There’s also
BufferedIterator[+A] specifying method
head: A, which is just like
next, but doesn’t advance the iterator.
Iterators implement all of the usual HOFs.
You can turn your own class into iterator by extending the trait, or you can create it ad-hoc:
To create a mutable variable instead of immutable value, use
var instead of
_ is a wildcard that will initialize the variable with the default value (0 for numbers,
null for reference types).
You can defer initialization of any
val by prefixing its declaration with
lazy keyword. This can also be used to avoid initialization order headaches.
To make functions accept their arguments by name (default is by value), prefix them with
Scala has all the traditional imperative control structures:
do-while loops (
for loops are present as for-comprehensions),
ifs with optional
return and so on. Note, though, that there’s no
continue for loops.
Minimal working program
You’re done with theory, now on to writing some real code! Oh wait, you don’t know how to compile stuff yet. Well, just head over to tpolecat’s blog and read “Setting up to write some Scala” — it’ll get you all set up in no time. He provides example program, too, so my job here is done.
Note of thanks
I’d like to thank kind people on firstname.lastname@example.org for answering my confused questions and explaining how things should be done. The same goes for attendees of #scala and #scalaz on Freenode — you people rock!
- clarify that
()(the type) is spelled
Unit, but the value is still
- elaborate on partial application (thanks dwins)
- remove an erroneous claim that lambda arguments should be type-annotated (thanks portnov & folex)
- explain that
Leaftype forms a singleton object (thanks folex)
Till next time! Minoru out.
Drop me a line! (wonder where’s the comments form?)