asoft
sea

~ tiny vessels of code slowly floating out to sea

Powered by a motorboat called the S.S.Tumblr

1 year ago

@10:58pm

Comments

implicitly subtle imports

One of Scala’s cheekier features, implicit declarations, can sometimes conjure up subtle gotchas. Besides being infamous for being a pimp, Scala’s implicits are also play the role of a magician by providing the illusion of default function arguments, a first class feature in 2.8.

I recently came across a subtle gotcha when using implicit function arguments, but first, it might be useful to catch up on a little background about Scala’s implicits.

Implicit wha?

One of Scala’s strong suits is freeing your tired little fingers from typing guessable information by inferring certain aspects about your code.

This same inference feature can provide you with the ability to sprinkle code with hints that will tell the compiler how to react to certain syntactic events, making statically typed code feel more dynamic.

Take the follow example of an implicit definition adds a ridiculous contrived BoomLike behavior to all strings

class BoomLike(str: String) {
  def boom = " %s ka-blam!!" format str
}
implicit def string2BoomLike(str: String) = new BoomLike(str)

You can now magically call the method boom on any String value.

"kitten".boom // kitten ka-blam!!

Implicits can also be used to define arguments in function definitions.

The following function will implicitly apply an implicitly defined value of b to the curried function fn

def fn(a: Int)(implicit b: Int) = a + b
implicit val b = 3
fn(2) // 5


What implicitly got me

I recently came across a use case for implicit function arguments that made me scratch my head.

Let’s say you have written shiny new library. This shiny new library contains some functions that you want to apply implicit defaults values for. You don’t want to obtrusively pollute the top level name space with them so you wrap them up in a module called Defaults. The result of this shiny new library might then look something like the following:

object Defaults {  
  implicit val height = 10
  implicit val frog = "geroro"  
}
def hop(distance: Int)(implicit height:Int) = distance * height

Pop quiz! What do you expect the execution of each to return?

// fig: A
import Defaults.height
hop(20)

// fig: B
import Defaults._
hop(20)

Time is up, kids!

When you to try and hop with figure A, you would fail miserably with an error stating:

error: no implicit argument matching parameter type Int was found.

You might find this odd, considering the value height is visible.

Were to you try and hop with figure B, you would get a value of 200.

I can’t yet provide a reasonable explanation of why. Can you?

blog comments powered by Disqus