# An introduction to implicit arguments

SBinary and Scalacheck are part of a small set of libraries that make extensive use of implicit arguments in a style very reminiscient of Haskell type classes. I’m hoping this style of programming will get more common in Scala – it’s a really useful technique and, in my completely unbiased opinion, both SBinary and Scalacheck are fantastic and you absolutely should use them. :-) But in order to do so you need to really understand how implicit arguments in Scala work.

This post is actually for work, as we’re using Scala there and this is a subject which has been confusing one of my colleagues.

As a starting point, in Scala you can declare a method to have multiple argument lists. This isn’t a fantastically useful feature, but here’s how it works:

scala> def foo(x : Int)(y : Int)
| = x + y
foo: (Int)(Int)Int

scala> foo(1)(2);
res1: Int = 3

scala> foo(1, 2);
:6: error: wrong number of arguments for method foo: (Int)(Int)Int
foo(1, 2);
^

scala> foo(1)
and value foo in object $iw of type => java.lang.String match expected type String  If there are multiple implicit arguments of the same type, it will fail as it has no way of choosing between them. But… ##### Implicit arguments of subtypes scala> def sayThings (implicit args : List[Any]) = args.foreach(println(_)) sayThings: (implicit List[Any])Unit scala> implicit val nothingNiceToSay : List[Any] = Nil nothingNiceToSay: List[Any] = List() scala> sayThings scala> implicit val hellos : List[String] = List("Hello world"); hellos: List[String] = List(Hello world) scala> sayThings Hello world  If you have an implicit argument of a subtype, it will also match as an implicit argument of this type. Moreover, if you have two implicit arguments which match and one is a subtype of the other, the more specific type will match. ##### Parameterized implicits scala> def implicitly[T](implicit t : T) = t implicitly: [T](implicit T)T scala> implicit val foo = "foo" foo: java.lang.String = foo scala> implicit val aUnit = () aUnit: Unit = () scala> implicitly[String] res2: String = foo scala> implicitly[Unit]  Type parameters can quite happily take part in the implicits mechanism. #### Defining implicit arguments So, we know how to use defined implicit arguments now. But how can we define them? We’ve seen one way: implicit val foo = "foo"; scala> implicitly[String] res2: String = foo  If this was all we could do then it wouldn’t be that powerful a feature. A nice to have, but ultimately not *that* exciting. Fortunately there are a few more things we can do. For starters, Scala has the uniform access principle, so any (wait, no. That would be too general. We can’t have features without special cases. Sigh. Ok, let’s say most) things you can do with a val you can do with a def implicit def foo = "foo" scala> implicitly[String] res2: String = foo  This def will be invoked each time we want the implicit. Here’s an example to demonstrate this scala> implicit def aUnit : Unit = println("Hello world") aUnit: Unit scala> implicitly[Unit] Hello world scala> implicitly[Unit] Hello world scala> implicitly[Unit] Hello world  In general, implicit defs shouldn’t have side effects. It can lead to some really counterintuitive behaviour. This is just for demonstration purposes. Now, the ability to use defs opens up a bunch of possibilities. For example, they can have type parameters: scala> implicit def emptyList[T] : List[T] = Nil; emptyList: [T]List[T] scala> implicitly[List[String]] res9: List[String] = List(Hello world) // Oops, we still had an implicit List[String] left over from an earlier example. Note how that was used in preference to the parameterized version. Let's try again. scala> implicitly[List[Int]] res10: List[Int] = List()  Moreover, implicit defs used in this way can themselves have implicit parameters. For example: scala> case class Foo[T](t : T); defined class Foo scala> implicit val hello = "Hello" hello: java.lang.String = Hello scala> implicit def foo[T](implicit t : T) = Foo[T](t) foo: [T](T)Foo[T] scala> implicitly[Foo[String]] res3: Foo[String] = Foo(Hello) ` (Note: I originally tried to write this example with Option. It turns out there’s a bug with how covariant types are handled which made it not work) The basic idea is that anything marked as implicit which you could write as a single identifier (possibly with a type signature to handhold the type inference system) is valid to be passed as an implicit argument. #### More reading This should provide enough to get you started. Your next step should probably be to check out the documentation for Scalacheck and SBinary (the latter of which is… less than stellar at the moment. I’ll fix that, I promise. :-)). If you’re looking for some slightly more hardcore reading, Generics of a Higher Kind has some interesting examples. Other than that, the best thing to do is play with some code. This entry was posted in programming and tagged , , on by . ## 10 thoughts on “An introduction to implicit arguments” 1. Michael Roger Has this changed recently? Your example behaves differently in my 2.6.0-final: wednet% scala Welcome to Scala version 2.6.0-final. scala> def sayThings (implicit args : List[Any]) = args.foreach(println(_)) sayThings: (implicit List[Any])Unit scala> implicit val nothingNiceToSay : List[Any] = Nil nothingNiceToSay: List[Any] = List() scala> sayThings scala> implicit val hellos : List[String] = List(“Hello world”); hellos: List[String] = List(Hello world) scala> sayThings <console>:11: error: ambiguous implicit values: both value hellos in object$iw of type => List[String]
and value nothingNiceToSay in object \$iw of type => List[Any]
match expected type List[Any]
val res2 = sayThings

(My scala 2.6.0 implementation behaves the way I expect: I don’t want scala arbitrarily choosing between a subtype value and a supertype value when both are in scope.)

2. David R. MacIver

Yes, it has. The implicits spec was incorrectly implemented prior to 2.6.1.

And regardless of what you want it to do, the new behaviour is both correct and useful. It’s also not arbitrary. :-)

3. Michael Roger

(Ignoring for a moment the unpleasantness of a feature being broken in one of its basic use cases through version 2.6.0-final :-( )

What is the rationale that justifies this decision that, for example, when matching an implicit Any,
a:String and a2:Int are ambiguous, but a1:String and a3:Any are not?

There is no connection between the values a1 and a3, except that the type of a1 happens to be a subtype of a3. Why should that fact be demonstrative in the search for an unambiguous match for a value of type a3?

To turn the question around in an example, suppose I have this:

implicit val obj:Any = new MyFoo();
def serialize(implicit arg:Obj) = …

def heartbeat(implicit arg:String) = println _

implicit val str:String = “still alive”

Adding the greeting() function silently changes the behavior of serialize(), even though there is no compiler warning or obvious clue in the source code as to why. That behavior contravenes the static type-safe component system one expects from Scala.

The Scala Reference mentions the rule but doesn’t explain it.

4. David R. MacIver

This isn’t actually one of the most basic use cases. Using implicit arguments like this has been historically regarded as quite subtle, and the specified behaviour is *really hard* to read. :-/ I’m just trying to convince people that it’s easy and useful. :-)

The short answer to why your particular suggested issue is not really a problem is that providing implicit values of particularly generic types like String and Any is kindof a bad idea. :-) Even without this subtyping behaviour there’s too much danger of unrelated things accidentally clobbering eachother. Generally when one uses these one defines a paramterised type specific to the use case and uses implicit arguments of that type.

The reason this behaviour is useful is that often what you want to do is something like provide a definition for serializing arrays, but provide a special case for serializing boolean arrays (because you end up inflating then by a factor of 8 as you only need one bit per boolean but end up using a byte in the default setup). So you define an implicit Binary[Array[T]] but also provide an implicit Binary[Array[Boolean]]. If there wasn’t some sort of resolution on subtype there would be no way to get this behaviour.

5. Michael Roger

Fair enough.

Throwing around implicit Anys, Strings, and Ints is certainly ill-advised; they were just the easiest examples I could think up to write.

The bit that worries me is that one reason I like statically-typed languages is that it’s hard to accidentally type something wrong that compiles but misbehaves. Implicits in general make it easier for my mistakes to typecheck :-) One just must be judicious in using implicits, and use discipline in organizing them.

I guess it’s fair to say that a programmer should always review all implicits in scope whenever any implicit is added, deleted, or modified. (I haven’t written enough Scala to know whether that means scanning the one enclosing source file or chasing down arbitrary ancestors of inheritance)

A compile flag “+Wnontrivial-implicit-resolution” would be a useful debugging tool, methinks.

I should read the sbinary code to see how it uses the implicit parameters and subtyping in a real use case.

6. uncial

Aren’t you being a bit hard on multiple argument lists? (“Hooray.”) They also provide support for currying:

def salesTax(ratePct : Double)(amount : Long) =
(amount * ratePct / 100.0D + 0.5D).toLong

def salesTaxGotham = salesTax(11.0D)_
def salesTaxOceanCity = salesTax( 8.5D)_
def salesTaxHomeTown = salesTax( 6.0D)_

def netCharge(taxer : (Long => Long), amts : Long*) = {
val subtotal = amts.foldRight(0L)(_ + _)
subtotal + taxer(subtotal)
}

println(“Gotham: ” + netCharge(salesTaxGotham, 10, 20, 30, 40))
println(“OceanCity: ” + netCharge(salesTaxOceanCity, 10, 20, 30, 40))
println(“HomeTown: ” + netCharge(salesTaxHomeTown, 10, 20, 30, 40))

which produces

Gotham: 111
OceanCity: 109
HomeTown: 106

so that a more general function (e.g. salesTax) can be used to construct more specialized functions by providing some, but not all, of the parameters.

7. David R. MacIver

The thing about Scala’s currying support is that it only works when the type inferencer is feeling smart enough to infer the result of the curried function type.

Given how poor the Scala type inferencer is, I tend to assume that anything which depends on it working properly doesn’t actually work. :-)

You can explicitly provide the result type, but this is not actually shorter than just using the cut notation.