ghik
ghik

Reputation: 10764

What's the point of generic type in foreach?

I'm curious - what is the point of generic type U in declaration of Traversable's foreach method?

def foreach[U](f: A => U): Unit

Since return type of Function1 is covariant, why can't that be just:

def foreach(f: A => Any): Unit

?

Upvotes: 20

Views: 1016

Answers (2)

idonnie
idonnie

Reputation: 1703

Maybe to allow you inherit from a Traversable, and make some use of return value U from f: A => U?

trait TraversableWithHandler[+A, E <: Option[Throwable]] extends Traversable[A] {
  override def foreach[U](f: A => U): Unit
  def handleError(t: E) 
}

For example in jQuery, return of false from inside foreach is equivalent to break, any different value is a continue.

Use Case

breakable { 
  List(1,2,3).foreach(_ match { 
    case 1 => println("ok")
    case 2 => 
      println("Sort of, soft interrupt?")
      return false
    case 3 => break
  })
}

Because the next code (parallel), never breaks (stackless throwable solution seems non-ideal in this case?):

import scala.util.control.Breaks._

breakable { 
  (0 to 100).toList.par.foreach(_ match { 
    case n if (n <= 50) => 
      println("#" * 100)
      try { break } catch { 
        case t: Throwable => println("" + t); break 
      }
    case n if (n > 50) => 
      println("" + n)
    case _ => "ok" 
  }) 
}

Upvotes: -5

P&#233;ter T&#246;r&#246;k
P&#233;ter T&#246;r&#246;k

Reputation: 116246

Not being Martin Odersky, I can only guess :-) Looking at the Scaladoc of foreach, I see this:

  /** Applies a function `f` to all elements of this $coll.
   *
   *  @param  f   the function that is applied for its side-effect to every element.
   *              The result of function `f` is discarded.
   *              
   *  @tparam  U  the type parameter describing the result of function `f`. 
   *              This result will always be ignored. Typically `U` is `Unit`,
   *              but this is not necessary.
   *
   *  @usecase def foreach(f: A => Unit): Unit
   */

So the return type of f doesn't matter and its result is always discarded. This, to me, suggests that using a generic type parameter here to mark the return type is just a documentation subtlety, saying "the return type can be anything, really anything, you like". Whereas a return type of Any may suggest to (some) readers some sort of limitation to the function types applicable here.

Another aspect is that Scala was very consciously designed to be generic from the ground up. So - to me - using a generic type parameter here is consistent with the general philosophy of the language, while using Any - although technically usable - would be a definitely non-generic approach which would be at odds with the rest of the language.

Upvotes: 10

Related Questions