I have a problem with types that I don't understand. In the code below I have two methods half1
and half2
which are exactly the same except half1
's return type is specified explicitly. Yet when I use the two methods in a foldLeft half
causes a compiler error. Here is the code. The line that sets val c
has the problem.
package org.bodhi.reactive.`try`
import scala.util.{Try, Success, Failure}
object Hello {
def main(args: Array[String]): Unit = {
val list = List(1,2,3)
Try(1024).flatMap(half1)
Try(1024).flatMap(half2)
half1(1024).flatMap(half1)
half2(1024).flatMap(half2)
val a = list.foldLeft(Try(1024))((accum, n) => accum.flatMap(half1))
val b = list.foldLeft(half1(1024))((accum, n) => accum.flatMap(half1))
val c = list.foldLeft(half2(1024))((accum, n) => accum.flatMap(half2)) // Compiler error
}
def half1(n: Int): Try[Int] =
if (n % 2 == 0) Success(n / 2)
else Failure(new Exception(s"WRONG $n"))
def half2(n: Int) =
if (n % 2 == 0) Success(n / 2)
else Failure(new Exception(s"WRONG $n"))
}
The error I get is:
[error] /home/chris/projects/reactive/example/src/main/scala/org/bodhi/reactive/try/Hello.scala:18: type mismatch;
[error] found : scala.util.Try[Int]
[error] required: Product with Serializable with scala.util.Try[Int]
[error] val c = list.foldLeft(half2(1024))((accum, n) => accum.flatMap(half2))
My question is: why does half1
comile in foldLeft, but half2
does not?
I am using scala 2.11.5
Both Success
and Failure
extend Try[T] with Product with Serializable
, (Product with Serializable
because they are case classes). So when you leave the return type off of half2
, it's returned type is inferred as Try[T] with Product with Serializable
.
Normally this doesn't matter, flatMap(half2)
will still return Try[T]
scala> Try(1024).flatMap(half2)
res2: scala.util.Try[Int] = Success(512)
But foldLeft
is a different story. The problem is when you pass half(2)
as the first argument. Let's look at the signature of foldLeft
:
def foldLeft[B](z: B)(op: (A, B) => B): B
B
is inferred from the argument z
, which means
B = Try[T] with Product with Serializable
That means that op
is expected to have the type:
(A, Try[T] with Product with Serializable) => Try[T] with Product with Serializable
But instead it's (A, Try[T]) => Try[T]
, and thus you get a type mismatch. Using type inference can be nice, but most of the time explicitly typing your return types will save you a lot of headaches.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With