1

Given:

scala> sealed trait Father
defined trait Father

scala> case object Son extends Father
defined object Son

and a type-class:

scala> trait Foo[A] 
defined trait Foo

Next, I defined the function, f, which, as I understand it, expects the type parameter, A, to be a sub-class of Father and have a typeclass instance of Foo.

scala> def f[A <: Father : Foo](x: Father): String = x.toString
f: [A <: Father](x: Father)(implicit evidence$1: Foo[A])String

Then, I defined an instance:

scala> implicit val fooFather = new Foo[Father] {}
fooFather: Foo[Father] = $anon$1@4f25b795

And lastly I called it:

scala> f(Son)
res0: String = Son

However, it seems to me that f could've been written as:

def f[A <: Father](x: Father)(implicit ev: Foo[A]): String = x.toString

Is there a preferred way of writing the above function f? And, is there a difference between them?

1
  • 1
    The REPL output from the first f clearly shows they are the same. Commented May 18, 2016 at 0:31

1 Answer 1

3

No, they are the exact same thing.

Context bounds, which btw is how Foo in def f[A <: Father : Foo] is called, has one problem. If in the body of the method you need to refer to the implicit parameter you end up needing to use implicitly[Foo[A]] which in inconvenient, ie

def f[A <: Father : Foo](x: Father): String = {
  implicitly[Foo[A]].ifFooHadAMethod // couldn't think of a better example :)
  x.toString
}

That's why in a lot of code out there people use

def f[A <: Father : Foo](x: Father)(implicit ev:Foo[A]): String = {
  ev.ifFooHadAMethod // couldn't think of a better example :)
  x.toString
}

Personally I prefer the 2nd case only if I need to refer to the implicit parameter, otherwise I prefer to use context bounds.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Why do you say that using implicitly[...] is inconvenient - since it's more to type than ev. ifFooHadAMethod?
Well, arguably inconvenient. You also need to provide the type, in this case, it's easy, but what if you need a projection like { type X[A] = Bar[A,B] }#X, for example? It's not only annoying, it's error prone, some times the trade off of using context bounds just don't pays off.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.