From ES6 to Scala: Advanced
statement. However, it can be used for much more, for example checking the type of input.
Pattern matching uses something called partial functions which means it can be used in place of regular functions, for
example in a call to
map. You can also add a guard clause in the form of an
if, to limit the match. If
you need to match to a variable, use backticks to indicate that.
Where pattern matching really shines is at destructuring. This means matching to a more complex pattern and extracting values inside that structure. ES6 also supports destructuring (yay!) in assignments and function parameters, but not in matching.
In Scala the destructuring and rebuilding have nice symmetry making it easy to remember how to do it. Use
_ to skip
values in destructuring.
In pattern matching the use of destructuring results in clean, simple and understandable code.
We could’ve implemented the Scala function using a
foldLeft, but it is more understandable using
collect and pattern matching. It would be read
as “Collect every person with a last name equaling
family and extract the age of those persons. Then sum up the ages.”
Another good use case for pattern matching is regular expressions (also in ES6!). Let’s extract a date in different formats.
Here we use triple-quoted strings that allow us to write regex without escaping special characters. The string is
converted into a
Regex object with the
.r method. Because regexes extract strings, we need
to convert matched groups to integers ourselves.
Typically higher-order functions are used to pass specific functionality to a general function, like in the case of
Array.prototype.filter in ES6 or
Seq.filter in Scala. We can use this to build a function to calculate a minimum and
maximum from a sequence of values, using a function to extract the target value.
Recursive functions can be very expressive, but they may also cause spurious stack overflows if the recursion gets too
deep. Scala automatically optimizes recursive functions that are tail recursive, allowing you to use them without
fear of overflowing the stack. To make sure your function is actually tail recursive, use the
which will cause the Scala compiler to report an error if your function is not tail recursive.
smart ES6 transpiler, it can actually convert a tail recursive function into a
while loop, but there are no checks
available to help you to verify the validity of tail recursion.
Partially applied functions
In Scala you can call a function with only some of its arguments and get back a function taking those missing arguments.
You do this by using
Function.prototype.bind function (although it limits you to providing parameters from left to right). For example we
can define a function to create HTML tags by wrapping content within start and end tags.
Multiple parameter lists
Let’s use currying to define the
tag function from previous example.
Multiple parameter lists also helps with type inference, meaning we don’t need to tell the compiler the types
explicitly. For example we can rewrite the
minmaxBy function as curried, which allows us to leave the
out when calling it, as it is automatically inferred from the first parameter. This is why methods like
defined with multiple parameter lists.
Being type safe is great in Scala, but sometimes the type system can be a bit prohibitive when you want to do something
else, like add methods to existing classes. To allow you to do this in a type safe manner, Scala provides implicits.
You can think of implicits as something that’s available in the scope when you need it, and the compiler can
into a Scala/Java
When these implicit conversion functions are in lexical scope, you can use JS and Scala dates interchangeably. Outside the scope they are not visible and you must use correct types or explicitly convert between each other.
Implicit conversions for “monkey patching”
a way of extending existing classes with new methods. It has several pitfalls in dynamic languages and is generally
The practice is known as polyfilling or shimming.
In Scala providing extension methods via implicits is perfectly safe and even a recommended practice. The Scala
standard library does it all the time. For example did you notice the
.toInt functions that were used on
strings in the regex example? Both are extension methods coming from implicit classes.
Let’s use the
convertToDate we defined before and add a
toDate extension method to
String by defining an implicit
String class (dangerous!), whereas the Scala version only
introduces a conversion from
String to a custom
StrToDate class providing an additional method. Implicit classes are
safe because they are lexically scoped, meaning the
StrToDate is not available in other parts of the program unless
explicitly imported. The
toDate method is not added to the
String class in any way, instead the compiler generates
appropriate code to call it when required. Basically
"2010-10-09".toDate is converted into
Scala IDEs are also smart enough to know what implicit extension methods are in scope and will show them to you next to the other methods.
Implicit extension methods are safe and easy to refactor. If you, say, rename or remove a method, the compiler will immediately give errors in places where you use that method. IDEs provide great tools for automatically renaming all instances when you make the change, keeping your code base operational. You can even do complex changes like add new method parameters or reorder them and the IDE can take care of the refactoring for you, safely and automatically, thanks to strict typing.
Finally we’ll make DOM’s
NodeList behave like a regular Scala collection to make it easier to work with them. Or to be
more accurate, we are extending
DOMList[T] which provides a type for the nodes.
NodeList is actually just a
Defining just those three functions, we now have access to all the usual collection functionality like
foldLeft, etc. This makes working with
NodeLists a lot easier and safer. The implicit class makes
use of Scala generics, providing implementation for all types that extend
asynchronous calls. This is affectionately known as callback hell. Then came the various
Promise libraries that
alleviated this issue a lot, but were not fully compatible with each other. ES6 standardizes the
interface so that all implementations (ES6’s own included) can happily coexist.
In Scala a similar concept is the
Future. On the JVM, futures can be used for both parallel
Future is a
placeholder object for a value that may not yet exist. Both
Future can complete successfully, providing
a value, or fail with an error/exception. Let’s look at a typical use case of fetching data from server using AJAX.
Here is a comparison between Scala’s
Promise for the most commonly used methods.
|The result of |
|Handles an error. The result of |
|Handles an error. |
|N/A||Creates a new future by filtering the value of the current future with a predicate.|
|N/A||Zips the values of |
|Returns a successful future containing |
|Returns a failed future containing |
|Returns a future that completes when all of the futures in the iterable argument have been completed.|
|Returns a future that completes as soon as one of the futures in the iterable completes.|
then is not type-safe, because it will flatten promises “all the way down”, even if that was not your intention.
map never flattens, and
flatMap always flattens once, tracking the appropriate static result type.
foreach is a slight variation of
map that does not return a new future.
It is typically used instead of
map to communicate the intent that the callback
is executed for its side-effects rather than its result value.
Futures from callbacks
Even though ES6 brought the standard promise API to browsers, all asynchronous functions still require the use of
callbacks. To convert a callback into a
Future in Scala you need to use a
Promise. Wait, what? Yes, in addition to
Future, Scala also has a
Promise class which actually implements the
As an example, let’s convert the
onload event of an
img tag into a
Because the image might have already loaded when we create the promise, we must check for that separately and just return a completed future in that case.
Next we’ll add an
onloadF extension method to the
HTMLImageElement class, to make it really easy to
use the futurized version.
While we are playing with DOM images, let’s create a future that completes once all the images on the page have
finished loading. Here we’ll take advantage of the
NodeListSeq extension class to provide us with the
NodeList returned from