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!
Related
I have a trait with a self-type annotation that has a type parameter. This trait is from a library and cannot be modified. I want to pass this trait to a function that will require an upper bound for the type parameter. For example, I have this code snippet:
sealed trait Job[K] { self =>
type T
}
case class Encoder[T <: Product]()
def encoder(job: Job[_])(implicit ev: job.T <:< Product): Encoder[job.T] =
new Encoder[job.T]()
This returns an error that Type argument job.T does not conform to upper bound Product and a warning that ev is never used. How should I design the encoder function?
Why it doesn't work?
Your issue has nothing to do with the generalized type constraint. You can remove it and still get the same error. A generalized type constraint is used to constrain the type of arguments the method can receive.
(implicit ev: job.T <:< Product) provides an evidence in scope that matches only if job.T <: Product, allowing only calls to the method with Job arguments where job.T <: Product. This is its purpose.
Your issue is because the Encoder class has its type parameter T <: Product. The generalized type constraint does not treat the type job.T itself as a subtype of Product, as you expected. The evidence only applies to value arguments, not to the type itself, because this is how implicit conversions work.
For example, assuming a value x of type job.T that can be passed to the method as an argument:
def encoder(job: Job[_])(x: job.T)(implicit ev: job.T <:< Product): Unit = {
val y: Product = x // expands to: ev.apply(x)
val z: Encoder[Product] = new Encoder[job.T] // does not compile
}
The first line compiles because x is expanded to ev.apply(x), but the second one cannot be expanded, regardless if Encoder is covariant or not.
First workaround
One workaround you can do is this:
def encoder[U <: Product](job: Job[_])(implicit ev: job.T <:< Product): Encoder[U] =
new Encoder[U]()
The problem with this is that while both type parameters U and T are subtypes of Product, this definition does not says much about the relation between them, and the compiler (and even Intellij) will not infer the correct resulting type, unless you specify it explicitly. For example:
val myjob = new Job[Int] {
type T = (Int, Int)
}
val myencoder: Encoder[Nothing] = encoder(myjob) // infers type Nothing
val myencoder2: Encoder[(Int, Int)] = encoder[(Int, Int)](myjob) // fix
But why use job.T <:< Product if we already have U <: Product. We can instead use the =:= evidence to make sure their types are equal.
def encoder[U <: Product](job: Job[_])(implicit ev: job.T =:= U): Encoder[U] =
new Encoder[U]()
Now the resulting type will be correctly inferred.
Second workaround
A shorter workaround is using a structural type instead:
def encoder(job: Job[_] { type T <: Product }): Encoder[job.T] =
new Encoder[job.T]()
Which is not only cleaner (doesn't require a generalized type constraint), but also avoids the earlier problem.
Both versions work on Scala 2.13.8.
Expanding on Alin's answer, you may also use a type alias to express the same thing like this:
type JobProduct[K, P <: Product] = Job[K] { type T = P }
// Here I personally prefer to use a type parameter rather than an existential
// since I have had troubles with those, but if you don't find issues you may just use
// JobProdut[_, P] instead and remove the K type parameter.
def encoder[K, P <: Product](job: JobProduct[K, P]): Encoder[P] =
new Encoder[P]()
This approach may be more readable to newcomers and allows reuse; however, is essentially the same as what Alin did.
I have a function like this:
case class SomeCaseClass(i: Int)
def func[T: Manifest](someArg: Int)(implicit i: String) = {
SomeCaseClass(2)
}
I need to call func and supply i explicitly
but when I call func[SomeCaseClass](2)("hello"), I get:
error: not enough arguments for method func: (implicit evidence$1:
Manifest[ScalaFiddle.this.SomeCaseClass], implicit i:
String)ScalaFiddle.this.SomeCaseClass. Unspecified value parameter i.
funcSomeCaseClass("hello")
Any way to do it without changing the function's signature?
You need to give all implicit parameters explicitly if you give any, and T: Manifest means there is an additional implicit parameter.
Happily, implicitly method will summon the implicit which the compiler would have supplied:
func[SomeCaseClass](2)(implicitly, "hello") // inferred to implicitly[Manifest[SomeCaseClass]]
When I define the method func in my scala REPL, I am finding the output as:
func: [T](someArg: Int)(implicit evidence$1: Manifest[T], implicit i: String)SomeCaseClass
In other words, the same code can also be written as:
def func1[T](someArg: Int)(implicit manifest: Manifest[T], i: String) = {
SomeCaseClass(2)
}
It is described here as well.
So in the above code, we can see that the implicit section now have two parameters, not the only String. And you need to provide all the params of the implicit section in case you want to fill them explicitly. If you're providing just one it will throw a compilation error.
Hence your method func can be called through the below code:
func(2)(Manifest.classType(classOf[SomeCaseClass]), "hello")
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 wrote this example
class TestMatch[T](private val t: T){
def test()(implicit ev: T <:< Option[Int]) = println(ev(t).get)
}
and a test for it
val tm = TestMatch(Some(10))
tm.test() //fine
val tm2 = TestMatch(10)
tm2.test() //compilation error
The question is who creates the implicit ev: T <:< Option[Int] when I invoke test method? I know I didn't. Maybe the compiler is aware of implicit <:< and know what to do with it.
Documenation of <:<was not quite clear
To constrain any abstract type T that's in scope in a method's
argument list (not just the method's own type parameters) simply add
an implicit argument of type T <:< U, where U is the required
upper bound; or for lower-bounds, use: L <:< T, where L is the
required lower bound.
Does it mean that the compiler will take the rest on itself? I just add the implicit ev: T1 <:< T2?
The first snippet compiles because of Predef.identity, which means you can always implicitly convert type T to type T (in this case Option[Int]). Otherwise, you would need to bring an implicit into scopre by yourself.
Does it mean that the compiler will take the rest on itself?
The compiler will search for an implicit in scope. If it finds a match, it will provide it, if it can't, you'll get a compilation error. With your example, the compiler finds that Some[Int] adheres to the implicit requirement of Some[Int] <:< Option[Int] as it is a direct subtype of Option[Int].
You can see this when compiling the code with scalac:
val tm: TestMatch[Some[Int]] = new TestMatch[Some[Int]](scala.Some.apply[Int](10));
tm.test()(scala.this.Predef.$conforms[Some[Int]]);
Where's for Int (your second example), there is no implicit in scope matching the requirement, and Int is not a subtype of Option[Int].
The compiler will try to look for implicit parameters in various predefined places. If it cant find them it will throw an error. This link might help: http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html
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