Looking at this spire method's signature:
implicit def complex[A: Fractional: Trig: IsReal: Dist]: Dist[Complex[A]]
What is the meaning of [A: Fractional: Trig ...]?
A context bound is a way of asserting the existence of an implicit value. For example, the method signature:
def complex[A : Fractional]
Means that there must be a value of type Fractional[A] available in scope when the method is called (so that the method body can use implicitly[Fractional[A]] to get an instance of that type). Compilation will fail if the compiler has no evidence of this fact. Context bounds are really syntactic sugar, so that the above method signature is equivalent to:
def complex[A](implicit ev: Fractional[A])
Multiple context bounds simply mean that we are making multiple such assertions about the generic parameter:
def complex[A : Fractional : Trig]
Means that there must be a values of types Fractional[A] and Trig[A] in scope when the method is called. So this method signature would be equivalent to:
def complex[A](implicit ev0: Fractional[A], ev1: Trig[A])
You can see this all in the REPL when you declare a method with the context bound syntax:
trait Foo[A]
trait Bar[A]
def foo[A : Foo : Bar] = ???
// foo: [A](implicit evidence$1: Foo[A], implicit evidence$2: Bar[A])Nothing
Related
I understand the following is an example of upper bound type parameterization in scala, where T must be a subtype of Command.
def getSomeValue[T <: Command] = ...
However, Today I found the following implementation of type parameterization with multiple parameter types and as I'm a beginner in scala, I'm quite unable to understand what actually it does. Is this means T must be subtype of either Command, Foo or Bar?
def getSomeValue[T <: Command : Foo : Bar] = ...
The stand-alone colon, in a type parameter specification, is actually shorthand (syntactic sugar) for a longer, and rather complicated, parameter invocation.
Example: def f[N: Numeric](n: N) = ...
is really: def f[N](n: N)(implicit ev: Numeric[N]) = ...
Meaning that when f(x) is invoked there has to be an implicit in scope that matches Numeric[x.type].
So, in your example code fragment: def getSomeValue[T <: Command : Foo : Bar] = ...
The compiler turns that into, roughly, the following:
def getSomeValue[T <: Command](implicit ev1: Foo[T], ev2: Bar[T]) = ...
We can demonstrate this by providing just enough skeletal code to actually make it compilable.
class Command {}
class Foo[F] {}
class Bar[B] {}
class Cmd extends Command
def getSomeValue[T <: Command : Foo : Bar](t: T) = t
getSomeValue(new Cmd)(new Foo[Cmd], new Bar[Cmd])
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// implicit parameters supplied explicitly
Is this means T must be subtype of either Command, Foo or Bar?
No, the upper bound is still required for T. You now must also have an implicit instance of Foo[T] and Bar[T] in scope when this method is called. This is called Context Bounds, and it syntax sugar for:
def getSomeValue[T <: Command](implicit f: Foo[T], b: Bar[T])
If you're unaware of what implicit means, refer to the documentation for more.
Consider the following REPL session:
# def test[C[X] <: TraversableOnce[X]](implicit cbf: CanBuildFrom[C[Int], Int, C[Int]]) = cbf()
defined function test
# test[List]
res32: collection.mutable.Builder[Int, List[Int]] = ListBuffer()
# def test[C[X] <: TraversableOnce[X]] = implicitly[CanBuildFrom[C[Int], Int, C[Int]]]
cmd33.sc:1: Cannot construct a collection of type C[Int] with elements of type Int based on a collection of type C[Int].
def test[C[X] <: TraversableOnce[X]] = implicitly[CanBuildFrom[C[Int], Int, C[Int]]]
^
Compilation Failed
The first definition of test function compiles and works, while the second one doesn't compile. The only difference between them is the way how the instance of CanBuildFrom is obtained. In first case it's declared as implicit parameter, requiring the compiler to find one. In second case it's invoked via implicitly function, which, in theory, should behave the same in terms of implicit search scope. What causes this behavior?
The definition of implicitly (in Predef) is:
def implicitly[A](implicit ev: A): A = A
It simply makes explicit to you an implicit already in scope (at the use site).
Now when you write this:
import collection.generic.CanBuildFrom
def test[C[X] <: TraversableOnce[X]]
(implicit cbf: CanBuildFrom[C[Int], Int, C[Int]]) = ???
You are asking the caller to provide an implicit (at the call site).
When you write
def test[C[X] <: TraversableOnce[X]] =
implicitly[CanBuildFrom[C[Int], Int, C[Int]]]
You are asking the compiler with the call implicitly to look-up an implicit already in scope. But you are not having any implicit of the given type in scope! So the two definitions of test are doing something entirely different.
You use implicitly normally to get hold of an implicit to which you don't have the name, because it was specified using the context-bounds or type-class notation, like def test[A: TypeClass]. You cannot use that notation here because CanBuildFrom has three type parameters and not one. So you cannot do much with implicitly here.
You could use implicitly with your first case:
def test[C[X] <: TraversableOnce[X]]
(implicit cbf: CanBuildFrom[C[Int], Int, C[Int]]) = {
implicit val onceAgain = implicitly[CanBuildFrom[C[Int], Int, C[Int]]]
assert(onceAgain == cbf)
}
But then you already know that you have that implicit with name cbf...
Note that you can get hold of an implicit CanBuildFrom for a known collection type:
implicitly[CanBuildFrom[List[Int], Int, List[Int]]] // works!
But this doesn't work if your collection type (C[X]) is abstract.
I have the following method:
def test[T](implicit ev: T <:< Int, t : T) = println(t)
How can I call it? I tried
test(10)
But the compiler prints out the following error:
Error:(19, 9) not enough arguments for method test: (implicit ev: <:<[T,Int], implicit t: T)Unit.
Unspecified value parameter t.
test(10)
^
First of all, I thought that we could just omit implicit parameters and specify only explicit ones. And secondly, why does it's saying that that the parameter t is implicit?
implicit t: T
How does it actually work?
First of all, I thought that we could just omit implicit parameters and specify only explicit ones.
You either specify all the implicits in the list, or you don't specify them at all. According to the specification, if one parameter is marked as implicit, the entire argument list is marked as well:
An implicit parameter list (implicit p1, ……, pn) of a method marks the parameters p1, …, pn as implicit.
secondly, why does it's saying that that the parameter t is implicit?
Because of what was answered in your first part.
If you still want to invoke it like that, you can use implicitly:
test(implicitly, 10)
Generally, it is recommended that you require an implicit in a separate argument list:
def test[T](i: Int)(implicit ev: T <:< Int) = println(t)
the problem is that the implicit parameter should be in its own list, like this:
def test[T](t : T)(implicit ev: T <:< Int) = println(t)
Give that a try!
In the following simplest example I have no compile errors:
object App {
def main(args: Array[String]) = {
test[Int]()
}
def test[T <: Int : ClassTag]() = println(implicitly[ClassTag[T]])
}
the program prints Int. But I don't understand why an object of type ClassTag[T] can be found for implicitly[ClassTag[T]] invocation? the only thing I did was to provide generic type argument. Where does the ClassTag[Int] come from?
The : symbol defines a context bound, which means that the compiler has to have an instance of ClassTag[T] in its implicit scope. It's syntactic sugar for the following:
def test[T <: Int]()(implicit $ev: ClassTag[T]) = println(implicitly[ClassTag[T]])
The call to implicitly will then take $ev as the required instance.
But this of course pushes the question a little bit further: where does the $ev (evidence) come from? To quote the Scala documentation (referring to TypeTag, but the same applies to ClassTag):
Given context bound [T: TypeTag], the compiler will simply generate an
implicit parameter of type TypeTag[T] and will rewrite the method to
look like the example with the implicit parameter in the previous
section.
The setup for this example (Scala 2.10.3):
trait S[A]
trait T[A]
implicit class X[A : S](a: A) { def foo() { } }
implicit class Y[A : T](a: A) { def foo() { } }
implicit object I extends S[String]
This compiles:
new X("").foo()
This doesn't:
new Y("").foo()
because there is no implicit T[String].
could not find implicit value for evidence parameter of type T[String]
new Y("").foo()
^
Therefore, I would assume that scalac could unambiguously apply the implicit conversion from String to X:
"".foo()
But instead we get:
type mismatch;
found : String("")
required: ?{def foo: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method X of type [A](a: A)(implicit evidence$1: S[A])X[A]
and method Y of type [A](a: A)(implicit evidence$1: T[A])Y[A]
are possible conversion functions from String("") to ?{def foo: ?}
"".foo()
^
Is this intentional? Is scalac not supposed to consider whether each conversion would actually work when it enumerates the candidates?
My nonacademic view is that implicit is by design not meant to work everytime it seems that it should work. I think it's a good idea otherwise you could easily get into an implicit hell. You could extend your example by adding more layers of implicit conversions. It would be hard to tell which function is actually called just by looking at the code. There are well-defined rules, but I remember simply that if it's not obvious from the code what's going on, it doesn't work.
I would say that your code breaks One-at-a-time Rule which leads to breaking the Non-Ambiguity Rule. A : S is just a syntactic sugar, and can be rewritten to:
implicit class X[A](a: A)(implicit e: S[A]) { def foo() { } }
implicit class Y[A](a: A)(implicit e: T[A]) { def foo() { } }
Without resolution of the "second" implicit level (method argument e) both classes X and Y look the same to the compiler and therefore are ambiguous. As the linked document says: "For sanity's sake, the compiler does not insert further implicit conversions when it is already in the middle of trying another implicit."