Reputation: 10764
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
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
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