From ES6 to Scala: Basics
This is a short introduction to the Scala language for those familiar with JavaScript ES6. We are comparing to ES6 instead of earlier versions of JavaScript because ES6 contains many nice features and syntax changes that bring it closer to Scala.
Best way to experiment with Scala is to use a Scala REPL, or the worksheet functionality in Scala IDE or IntelliJ IDEA.
For more reading check out Scala Exercises, Scala School and official Scala Tutorials.
Scala language
Scala is a modern multi-paradigm programming language designed to express common programming patterns in a concise, elegant, and type-safe way. It smoothly integrates features of object-oriented and functional languages. Scala is a pure object-oriented language in the sense that every value is an object. It is also a functional language in the sense that every function is a value.
The biggest difference to JavaScript is that Scala is statically typed. This means that it is equipped with an expressive type system that enforces statically that abstractions are used in a safe and coherent manner, meaning the compiler will catch many typical programming errors. If you have used other statically typed languages like Java or C# before you may have noticed that type definitions are all over the place. This is not true with Scala where the compiler can infer most of the types automatically.
Variables
Let’s start with something simple, variables. Both Scala and ES6 support mutable and immutable variables.
ES6
Scala
Note that the Scala compiler automatically infers the types for x
and y
from the values that are assigned. In Scala
both mutable and immutable variables must always be initialized when declared.
Primitive types
Scala defines several primitive types, of which most have corresponding types in JavaScript as well. See the table below.
Scala type | JavaScript type | Notes |
---|---|---|
String | string | |
Boolean | boolean | |
Char | N/A | UTF-16 code unit |
Byte | number | integer, range (-128, 127) |
Short | number | integer, range (-32768, 32767) |
Int | number | integer, range (-2147483648, 2147483647) |
Long | N/A | 64-bit integer |
Float | number | 32-bit floating point |
Double | number | 64-bit floating point, fully equivalent to JS number |
Unit | undefined | |
Null | null |
In JavaScript all numbers are represented as 64-bit floating point internally, which may give surprising results when
making some calculations. In Scala calculations are always performed using the types of operands, so dividing an Int
with another Int
, the result is rounded to an Int
.
ES6
Scala
Because in JavaScript every number is a number
there is no need to do type conversions. In Scala, however, it is an
error if you try to assign a higher precision value to a lower precision variable. You must explicitly convert it using
an appropriate function.
Scala
Actually the numeric types Int
, Short
, Byte
and Float
also exist in JavaScript if you use typed
arrays. These are not commonly used in regular
JavaScript code, but for some specific purposes, like WebGL, they are required.
Functions
Defining functions is quite similar in both languages. You just replace the function
keyword with def
and add types
for function parameters and return type. In Scala you can omit the return
keyword as the last expression in the
function is automatically used as the return value. Return type is usually automatically inferred by the Scala compiler
(when not using return
), but it is good practice to define it to help catch potential type errors.
ES6
Scala
Anonymous functions
In functional programming you quite often need to provide a function as a parameter, but you don’t need it elsewhere so it can be anonymous. Both languages support the nice “fat arrow” notation for defining anonymous functions conveniently.
ES6
Scala
Default, named and rest parameters
You can also define default values for parameters if they are not supplied when the function is called. For variable
number of parameters, you can access those as a Seq
. Named parameters work just as you would expect in Scala, whereas
in ES6 you need to supply them with the object notation.
ES6
Scala
Again, Scala compiler can infer all the required types in the code above, including the parameters for the anonymous
function given to the foldLeft
function.
if
, while
, for
, match
control structures
As you would expect, Scala has the regular if-else
and while
control structures found in most programming
languages. The big difference to JavaScript is that if
statements are actually expressions returning a value. In
JavaScript you have the special a ? b : c
construct to achieve the same result.
ES6
Scala
The for
construct in Scala is quite different from the for-loop in JavaScript and also much more powerful. You can use
it to iterate over numerical ranges or collections in both languages:
ES6
Scala
In case you have nested for-loops, you can easily combine them into one for-comprehension in Scala. Inside the for
you can even filter using if
expressions. In Scala a for-comprehension is just syntactic sugar for a series of
flatMap
, map
and withFilter
calls making it very handy when dealing with Scala collections.
ES6
Scala
The code above also serves as an example for string interpolation (in Scala) and template strings (in ES6). Both
make it easier to construct strings using variables or function calls. In Scala you don’t need to enclose the variable
in {} if it’s just a simple variable name. For more complex cases you’ll need to use the s"Length = ${data.length}"
syntax.
Finally the match
construct provides pattern matching capabilities in Scala. Pattern matching is a complex topic
covered in more detail in the advanced section of this article, so here we just focus on the simple use cases like
replacing JavaScript switch
/case
with it.
ES6
Scala
In Scala you can use the |
-operator to match multiple choices and there is no need (nor support) for break
, as cases
never fall through like they do in JavaScript. For the default case, use the ubiquitous _
syntax (it has many many
more uses in Scala!) As with if
, a match
is an expression returning a value that you can directly assign to a
variable.
Classes
Being an object-oriented language, Scala naturally supports classes with inheritance. In addition to basic classes Scala also has:
case class
es for conveniently storing dataobject
s for singletonstrait
s for defining interfaces and mixins
A simple class hierarchy can be achieved in both languages.
ES6
Scala
Even though Scala has the concept of this
it is not that often used in your own code.
Case classes
When reading Scala application code you will probably encounter more case class
es than regular class
es. This is due
to their special features that make them so useful. First of all you don’t need to use new
keyword when instantiating
them and all constructor parameters are automatically available as public fields. Case classes also have default
implementations for toString
and equality making them convenient to use as data objects.
JavaScript doesn’t quite have a similar construct, but whenever you would use the regular object notation, consider using a case class instead.
ES6
Scala
Case classes enforce type safety and prevent constructing invalid objects with missing fields.
Scala compiler automatically generates a proper equals
method for case classes, making comparing them trivial. In ES6
you would typically go for a library like lodash to avoid writing the complex
comparison code yourself.
ES6
Scala
Fields in case classes are immutable by default (unless you define them with var
modifier) so you cannot make changes
to instances. Instead of modifying the instance you make a copy and modify one or more fields during the copy. Scala
provides a suitable copy
function for each case class automatically. In ES6 you can use Object.assign
to achieve the
same result.
ES6
Scala
Finally case classes can be used nicely in pattern matching, which is covered in the advanced section.
Objects
An object
is a special class with only a single instance: a singleton. JavaScript also has a singleton design pattern
(or actually several) even though the language itself does not have direct support for the concept. Singletons are
useful for putting stuff in a shared namespace without polluting the global scope. Scala singletons are lazy in the
sense that they are initialized only when first accessed. In JavaScript you can achieve lazyness, but typically it’s
not done as it makes things complicated.
ES6
Scala
As you can see, defining singleton objects in Scala is quite trivial thanks to the native support in the language.
Another common use for object
s in Scala is using them as companion objects for classes to store static variables
and methods shared by all instances of the class.
Traits
Scala trait
s are similar to the mixin design pattern in JavaScript by allowing developer to define behaviors for class
composition. Because of Scala’s strict type system, traits are commonly used to describe common interfaces for a group
of implementation classes. JavaScript itself has no need for interfaces, but some extensions like TypeScript support
them for the same purpose as Scala.
ES6
Scala
Note that there are many ways for defining mixins in JavaScript, using Object.assign
is just one of them supported by
ES6.
Option
, the type safe undefined
The notorious undefined
type in JavaScript can be a blessing or a curse. On the other hand it makes life easy by
allowing you to drop function parameters or leave variables undefined. But then it also masks many errors and makes
you write extra code to check for undefined
. Quite often undefined
is used to make a distinction between an
existing value (of any type) and a missing value.
Scala doesn’t have undefined
(it does have null
but its use is discouraged), but instead it has an
Option
trait for representing optional values. In Scala.js the undefined
type exists to support
interoperability with JS libraries, but even there it is recommended to use Option
whenever possible.
Option[A]
is a container for an optional value of type A
. If the value of type A
is present, the Option[A]
is an
instance of Some[A]
, containing the present value of type A
. If the value is absent, the Option[A]
is the object
None
.
ES6
Scala
Pattern matching works nicely with Option
, but there are more powerful ways to use it. Let’s rewrite the previous
function another way giving us the same result.
Scala
Whoa, quite a reduction in code size! Next let’s see how we can process a sequence of option values.
ES6
Scala
Option
provides many collection like methods like map
, filter
and flatMap
, which are discussed in the next
chapter.