Foreach signatures

So when creating a foreach method, or a foreach like method in ones own code, of which I have quite a number, what is the current recommended signature?

def foreach[U](f: Element => U): Unit //or
def foreach(f: Element => Unit): Unit

The standard library obviously uses the former. But that often means adding the Unit value “()” at the end of implementations to avoid a warning. Is the U parameter still necessary?

Would Element => Nothing not be really universal

No, Element => Nothing is the subtype of all functions that receive an Element, as such no function would be valid, because you can not pass a super type when a subtype is expected.

The point of using U or Any is to allow reuse of previous functions. For example:

var acc = 0
def addAndGetPrevious(x: Int): Int = {
  val previous = acc
  acc += x
  previous
}

numbers.foreach(addAndGetPrevious)

And the reason to use U instead of Any is to help inference.

Actually that code would also work if foreach accepted only Int => Unit functions. It’s only a “problem” when you have an actual function value.

scala> case class Foo(a: Int) { def foreach(f: Int => Unit): Unit = f(a) }
class Foo

scala> var acc = 0
     | def addAndGetPrevious(x: Int): Int = {
     |   val previous = acc
     |   acc += x
     |   previous
     | }
var acc: Int = 0
def addAndGetPrevious(x: Int): Int

scala> Foo(42).foreach(addAndGetPrevious)

scala> acc
val res11: Int = 42

scala> val f = addAndGetPrevious _
val f: Int => Int = $Lambda$6412/1491193970@558e51a4

scala> Foo(42).foreach(f)
                       ^
       error: type mismatch;
        found   : Int => Int
        required: Int => Unit

Which again goes to show what a nice toolbox cats is:

scala> import cats.implicits._
import cats.implicits._

scala> Foo(42).foreach(f.void)

scala> acc
val res14: Int = 84
2 Likes

Nothing as a return type means it never returns. For example, because it will always throw an exception.

f: A => Any if you don’t like the cats route.

When does the first definition require you to add () at the end?

trait Triangle extends Polygon3Plus {
  override def foreachVert[U](f: Vec2 => U): Unit = { f(v1); f(v2); f(v3) }

compiling 1 Scala source to /Common/openstrat/SbtDir/GraphicsCore/target/scala-2.13/classes ...
[warn] /Common/openstrat/Graphics/src/polygon/Triangle.scala:23:69: discarded non-Unit value
[warn] 	override def foreachVert[U](f: Vec2 => U): Unit = { f(v1); f(v2); f(v3) }

Oh I see. I thought you meant while calling the foreach method, which seems more likely to give warnings with the second definition.