Implicit Parameters in Scala and Haskell
...and also C++ (kinda).
Do not say a little in many words, but a great deal in a few.
– Pythagoras
What the heck are implicit parameters?
In software engineering, the Don’t Repeat Yourself principle is one of the foundations of writing modular programs. Implicit parameters (implicits, for short) are one of those language features which hide repetitive code so that developers can focus on the more important aspects of logic. Not all programming languages have implicit parameters; but those that do provide an extra mechanism to deal with repetitive code.
Both Scala and Haskell have the notion of implicit parameters. In Scala, it’s a built-in feature; whereas in Haskell, it’s a language extension. An even more important distinction is that in Scala, implicit variables bind by type, whereas in Haskell, they bind by name. We'll take a look at these in more detail.
Examples
...in Scala
Let's take a look at what implicit parameters look like in Scala.
(Demo)
As shown above, implicit params are coded by introducing a new set of parameters (in fact, this is how currying is achieved in Scala). In Scala, implicit variables require the implicit
keyword. This serves as a flag to the compiler saying “this variable can be passed to functions with implicit parameters”. (Well, not exactly, but you get the idea.)
This is pretty useful for variables that have a single instance in any context and act like a global variable. In the Spark framework, a SparkSession
is used to configure spark options, memory usage, and more. After configuration, we still want to hold onto the returned object in order to call functions such as spark.sql
. Typically, we would only have one SparkSession
in an application, so it makes sense to pass it to helper functions implicitly.
One gotcha is that Scala searches the calling context for implicit parameters of a matching type. The variable name does not matter. Scala implicits are actually a tad more complicated (and much more powerful as a result), so my example here doesn’t do it justice.
...in Haskell
Haskell’s implicit parameters are different. Here’s an example:
(Demo)
Note that implicit variables in Haskell need to be indicated with a question mark, similar to the implicit
keyword in Scala. ?cmp
is an implicit variable, but cmp
isn’t. However, unlike Scala, the implicit parameters here are specified in the function’s type signature. And not just that, it’s written in the function’s type constraints.
In Haskell, functions type signatures are placed on a separate line. For example, sortBy
has the signature (a -> a -> Ordering) -> [a] -> [a]
, meaning it takes a function (in this case, a comparator) which itself takes two generic a
's, a list of a
's, and returns a list of a
's. (This is not what actually happens under the hood, but it’s good enough for now.) On the other hand, sort
's type signature looks a little different:
In a Haskell type signature, stuff on the left of =>
are type constraints; here we have ?cmp :: a -> a -> Ordering
. Although somewhat unintuitive, this leverages Haskell’s existing type system so that implicit parameters are automatically propagated. So if another function calls sort
without a ?cmp
, then that function will also have ?cmp :: a -> a -> Ordering
in its type constraint!
On a different note, an important distinction is that instead of searching for variables with a matching type (as in Scala), Haskell searches for variables with the same name. In a way, this behaves like C/C++ macros, but with type safety. Compare the Haskell example to the following C++ example.
...in C++
(Demo)
This example irks me since it uses macros, so it's a bit hacky... too hacky for my tastes.
Abuse of Implicits
Although implicit params remove the need to explicitly state params, there is also the danger of hiding too much. This may lead to code being harder to trace and debug, and hence may cause confusion among team members.
The similarity with natural languages is striking. Sometimes ambiguity may arise when people conversing don’t have sufficient context. Or misunderstanding may arise when people come from different cultures.
Coming back to software engineering, implicits are best reserved for extremely common variables and unique types. Think twice before slapping implicit
or a question mark in your code. You’ll thank yourself later.
Further Reading:
- Tour of Book: Implicit Parameters
- Where does Scala look for implicits?
- GHC Language Extensions: Implicit Parameters
- Implicit Parameters: Dynamic Scoping with Static Types: Basis for implicit params in Haskell. Good academic foundation and examples.
Comments are back! Privacy-focused, without ads, bloatware, and trackers. Be one of the first to contribute to the discussion — I'd love to hear your thoughts.