As I study about Scala, I open see implicitly. But, every time I see this, I just ignore just thinking like “It’s syntactic sugar of implicit”. This time, I write this post to really under stand this.
In Scala, implicitly is just this.
def implicitly[T](implicit e: T) = e
That’s all! implicitly is a function just get implicit e instance and return e. Then, what is an advantage of using implicitly?
Example 1
You can use implicit like this.
implicit val optionInt: Option[Int] = Some(1) implicit val optionBoolean: Option[Boolean] = Some(true) def getImplicitInt(implicit oInt: Option[Int]): Int = oInt.get def getImplicitBoolean(implicit oBoolean: Option[Boolean]): Boolean = oBoolean.get getImplicitInt // res0: Int = 1 getImplicitBoolean // res1: Boolean = true
Now, you can use just same by using implicitly
implicit val optionInt: Option[Int] = Some(1) implicit val optionBoolean: Option[Boolean] = Some(true) def getImplicitlyA[A: Option]: A = implicitly[Option[A]].get getImplicitlyA[Int] // res2: Int = 1 getImplicitlyA[Boolean] // res3: Boolean = true
Implicitly can use in such situation.
Implicitly can use when you want to get implicit instance which have 1 type parameter.
As you can see above, by using ‘Implicitly[Option[Int]]’, you can get implicit instance ‘Option[Int]’. It has 1 type parameter Int.
Example 2
Then how about implicitly for the type which has no type parameter? For example, implicit can do like this.
implicit val string: String = "Hello" implicit val boolean: Boolean = true implicit val int: Int = 0 def getImplicitT[T](implicit t: T): T = t getImplicitT[Int] // res0: Int = 0 getImplicitT[String] // res1: String = Hello getImplicitT[Boolean] // res2: Boolean = true
But, if you do the same with implicitly, errors occur.
def getImplicitlyT[T]: T = implicitly[T] getImplicitlyT[Int] getImplicitlyT[String] getImplicitlyT[Boolean] // compile error: not enough arguments for method implicitly: (implicit e: T)T. Unspecified value parameter e. def getImplicitlyT[T]: T = implicitly[T] ^
Yes, because I mentioned above, implicitly can be used the type which has a type parameter. Then how can we use implicitly in this situation? The answer is ‘make Id type’.
type Id[A] = A def getImplicitlyT[T : Id]: T = implicitly[Id[T]] getImplicitlyT[Int] // res3: Int = 0 getImplicitlyT[String] // res4: String = Hello getImplicitlyT[Boolean] // res5: Boolean = true
I make new type Id which has one type parameter. And Id[A] is same as A. So, you can use just like implicit
Context bound
Right side of function ‘getImplicitlyAt’ has type parameter(A : Option). It looks like type bound. But it is called Context bound. Type bound is ‘<:’.You can see type bound in Scala School. In context bound, it doesn’t mean that A is Option. Instead, A will be a type passing to Option.
implicit val optionInt: Option[Int] = Some(1) | |
implicit val optionBoolean: Option[Boolean] = Some(true) | |
def getImplicitOptionInt(implicit oInt: Option[Int]): Int = oInt.get | |
def getImplicitOptionBoolean(implicit oBoolean: Option[Boolean]): Boolean = oBoolean.get | |
getImplicitOptionInt | |
getImplicitOptionBoolean | |
def getImplicitlyOptionA[A: Option]: A = implicitly[Option[A]].get | |
getImplicitlyOptionA[Int] | |
getImplicitlyOptionA[Boolean] | |
trait Parent { | |
def sayHello: String | |
} | |
trait Son extends Parent { | |
override def sayHello: String = "Hello! I'm Son!" | |
} | |
trait Daughter extends Parent { | |
override def sayHello: String = "Hello! I'm Daughter!" | |
} | |
def sayHello[A <: Parent](a: A): Unit = println(a.sayHello) | |
sayHello(new Son {}) | |
sayHello(new Daughter {}) |
implicit val string: String = "Hello" | |
implicit val boolean: Boolean = true | |
implicit val int: Int = 0 | |
def getImplicitT[T](implicit t: T): T = t | |
getImplicitT[Int] | |
getImplicitT[String] | |
getImplicitT[Boolean] | |
type Id[A] = A | |
def getImplicitlyT[T : Id]: T = implicitly[Id[T]] | |
getImplicitlyT[Int] | |
getImplicitlyT[String] | |
getImplicitlyT[Boolean] |