Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to provide default value for implicit parameters at class level

Tags:

I'm trying to define a class with some methods taking an implicit parameter :

object Greetings {   def say(name: String)(implicit greetings: String): String = greetings + " " +name  } 

I use this class from another class

implicit val greetings = "hello"                //> greetings  : java.lang.String = hello Greetings.say("loic")                           //> res0: String = hello loic Greetings.say("loic")("hi")                     //> res1: String = hi loic 

My problem is that it works only if I define the implicit val outside my Greetings object. I would like to be able to provide methods with implicit parameters, with a default value inside my class, to make easier the use of my API (like Scala collection API).

So I would like to do this, but it's not working (implicit value not found) :

object Greetings {   implicit val greetings = "hello"       def say(name: String)(implicit greetings: String): String = greetings + " " +name  } 

and then

Greetings.say("loic")                          Greetings.say("loic")("hi")  

I know I can define a default value with (implicit greetings: String = "hello") but I would like to do it at class level, to avoid repeating if there are many methods.

I guess I'm missing something because I saw that CanBuildFrom is defined inside the List class, for example.

like image 604
Loic Avatar asked Oct 07 '12 07:10

Loic


People also ask

How do you pass an implicit parameter?

The implicit parameter in Java is the object that the method belongs to. It's passed by specifying the reference or variable of the object before the name of the method. An implicit parameter is opposite to an explicit parameter, which is passed when specifying the parameter in the parenthesis of a method call.

What are implicit parameters?

What Are Implicit Parameters? Implicit parameters are similar to regular method parameters, except they could be passed to a method silently without going through the regular parameters list. A method can define a list of implicit parameters, that is placed after the list of regular parameters.


1 Answers

It is a bad idea to use such a general type as String in an implicit. The main reason is that implicit lookup is solely base on the type, so what if someone else defines another implicit value of type String? You might end up with a conflict. So you should define your own specific type for your own purpose (a simple wrapper around String).

Another reason is that when looking for implicit values, the compiler will look (among other places) into the companion object (if any) of the implicit value type. You can easily see how useful it is, as the companion object is the natural place to put a default implicit value (as in your case). But if the implicit value is of a type that you don't own (such as String) you just cannot write a companion object for it, while with your own wrapper type there is no problem.

OK, enough verbiage, here is how you can do it:

case class Greetings( value: String ) {   override def toString = value } object Greetings {   // this implicit is just so that we don't have to manually wrap    // the string when explicitly passing a Greetings instance   implicit def stringToGreetings( value: String ) = Greetings( value )     // default implicit Greetings value   implicit val greetings: Greetings ="hello"    def say(name: String)(implicit greetings: Greetings): String = greetings + " " +name  } Greetings.say("loic")                          Greetings.say("loic")("hi")  
like image 87
Régis Jean-Gilles Avatar answered Oct 04 '22 18:10

Régis Jean-Gilles