Using Scala implicits

We have addressed implicits in the previous chapters, but here we are going to see more examples. Implicit parameters are very similar to default parameters but they use different mechanisms in order to find the default value.

An implicit parameter is one that is passed to a constructor or a method and is marked as implicit, which means that the compiler will search for an implicit value within the scope if you don't provide a value for this parameter. For example:

scala> def func(implicit x:Int) = print(x) 
func: (implicit x: Int)Unit
scala> func
<console>:9: error: could not find implicit value for parameter x: Int
func
^
scala> implicit val defVal = 2
defVal: Int = 2
scala> func(3)
3

Implicits are very useful for the collection API. For example, the collections API use implicit parameters to supply CanBuildFrom objects for many methods in these collections. This happens usually because users aren't concerned with these parameters.

One constraint is that you can't have more than one implicit keyword per method and it must be at the start of the parameter list. Here are some invalid examples:

scala> def func(implicit x:Int, y:Int)(z:Int) = println(y,x)
<console>:1: error: '=' expected but '(' found.
def func(implicit x:Int, y:Int)(z:Int) = println(y,x)
^
Number of implicit parameters: Note that you can have more than one implicit parameter. But, you cannot have more than one group of implicit parameters.

The following is for more than 1 implicit parameter:

scala> def func(implicit x:Int, y:Int)(implicit z:Int, f:Int) = println(x,y)
<console>:1: error: '=' expected but '(' found.
def func(implicit x:Int, y:Int)(implicit z:Int, f:Int) = println(x,y)
^

The final parameter list on a function can be identified or marked as implicit. This means the values will be taken from the context as they are being called. In other words, if there is no implicit value of the exact type in the scope, the source code using implicit will not be compiled. The reason is simple: since the implicit value must be resolved to a single value type, it would be a better idea to make the type specific to its purpose to avoid implicit clashes.

Moreover, you do not require methods to find an implicit. For example:

// probably in a library
class Prefixer(val prefix: String)
def addPrefix(s: String)(implicit p: Prefixer) = p.prefix + s
// then probably in your application
implicit val myImplicitPrefixer = new Prefixer("***")
addPrefix("abc") // returns "***abc"

When your Scala compiler finds an expression of wrong types for the context it is feeding, it will look for an implicit function value instead for type-checking. So, the difference between your regular methods is that the one marked implicit will be inserted for you by the compiler when a Double is found but an Int is required. For example:

scala> implicit def doubleToInt(d: Double) = d.toInt
val x: Int = 42.0

The earlier code will work the same as:

scala> def doubleToInt(d: Double) = d.toInt
val x: Int = doubleToInt(42.0)

In the second we've inserted the conversion manually. At first, the compiler did this automatically. The conversion is required because of the type annotation on the left-hand side.

While working with data, we will often need to convert one type to another. Scala implicit type conversion gives us this facility. We will see several examples of it in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.20.193