Tim Stewart Tim Stewart - 1 month ago 16
Scala Question

What Scala implicit conversion on a Seq is happening here?

I'm reading Debasish Ghosh's new book, "Functional and Reactive Domain Modeling" and I'm really enjoying it.

One thing in Chapter 5 that has me puzzled is how the line below:

Reporting.report(accts).foreach(println _)


can take a Seq[Account] and convert it to a Seq[Show]. I know implicits are at play but what steps are the compiler taking to allow this to compile? Is this just a specific instance of a more general implicit rule? It seems like the compiler is mixing the Show trait into the Account objects. Thanks!

Adapted from page 164:

import scala.util.Try

trait Show[T] {
def shows(t: T): Try[String]
}

trait ShowProtocol {
implicit val showAccount: Show[Account]
implicit val showCustomer: Show[Customer]
}

trait DomainShowProtocol extends ShowProtocol {
override implicit val showAccount: Show[Account] = (t: Account) => Try("Account")
override implicit val showCustomer: Show[Customer] = (t: Customer) => Try("Customer")
}

case class Account()
case class Customer()

object Reporting {
def report[T: Show](as: Seq[T]): Seq[Try[String]] = as.map(implicitly[Show[T]].shows _)
}

object DomainShowProtocol extends DomainShowProtocol

object Main {
def main(args: Array[String]): Unit = {
import DomainShowProtocol._

val accts: Seq[Account] = Seq(
Account(),
Account(),
Account()
)

Reporting.report(accts).foreach(println _)
}
}

Answer

Syntactic sugar

def report[T: Show](seq: Seq[T]) 

is syntactic sugar for

def report(seq: Seq[T])(implicit evidence: Show[T])

roughly you can assume

[T: Show]

does the job of

(implicit evidence: Show[T])

implicitly[Show[T]]

is nothing but the reference of the implicit Show[T]

trait DomainShowProtocol has a implicit evidence Show[Account]

object DomainShowProtocol extends DomainShowProtocol

Now using the object DomainShowProtocol implicit is imported into scope.

report method is able to convert Seq[Account] to Seq[Try[String]] because of the implicit evidence from object DomainShowProtocol which in turn is coming from trait DomainShowProtocol

def report[T: Show](as: Seq[T]): Seq[Try[String]] = as.map(implicitly[Show[T]].shows _)

above function is the syntactic sugar for

def report(as: Seq[T])(implicit evidence: Show[T]): Seq[Try[String]] = as.map(evidence.shows _)

Here T is Account and implicit evidence Show[Account] is comming from the object DomainShowProtocol. Thats how this conversion is possible.