Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala type error with Try[Int]

Tags:

scala

foldleft

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

like image 657
Christopher Helck Avatar asked Jan 31 '15 16:01

Christopher Helck


Video Answer


1 Answers

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.

like image 148
Michael Zajac Avatar answered Oct 14 '22 03:10

Michael Zajac