Question

I have the following code in a method:

aSides.foreach(as => as.side.terr match
{
  case r: TerrSRiver => paintSeq :+= ((g: Graphics2D) =>
    {
      g.setPaintColour(ColourInt.blue)
  g.fill(Polygon(as.paintStd(0.2)))
    }
  case _: TerrSCoast => paintSeq :+= ((g: Graphics2D) =>
    {
      g.setPaintColour(TerrSea.colour)
      g.fill(Polygon(as.paintStd(0.2)))
    }) //one case excluded for simplicity

paintSeq is declared outside the method

var paintSeq: Seq[Graphics2D => Unit] = Nil

This compiles and runs as expected. However if I add an if Statement to the first case:

case r: TerrSRiver => paintSeq :+= ((g: Graphics2D) =>
  {
    g.setPaintColour(ColourInt.blue)
    g.fill(Polygon(as.paintStd(0.2)))
    if (zoom > 50) g.setPaintColour(ColourInt.white)
  }

I get an error:

type mismatch; found : Seq[swing.Graphics2D => Any] required: Seq[swing.Graphics2D => Unit] AreaESw.scala /prStratSw/src/pGrid/pUISw line 49 Scala Problem

The error refers to the paintSeq :+= method. Why is the if statement returning Any rather than Unit? I can get rid of the error by adding a line after the if statement:

val dummy = 0

However if I add in return Unit at the end:

case r: TerrSRiver => paintSeq :+= ((g: Graphics2D) =>
  {
    g.setPaintColour(ColourInt.blue)
    g.fill(Polygon(as.paintStd(0.2)))
    if (zoom > 50) g.setPaintColour(ColourInt.white)
    return Unit
  }

It Compiles with the following warning:

enclosing method setVisObjs has result type Unit: return value discarded

But when it runs I get the following error

Exception in thread "AWT-EventQueue-0" scala.runtime.NonLocalReturnControl$mcV$sp

Using "return ()" still gives the run time exception.

This is Scala Swing code, but I'm using Scala 2.10.3 in the JavaFx Eclipse download: 4.2.2 on Linux.

Was it helpful?

Solution

Type of if

The result type of if (cond) expr is the common base type of expr and Unit, just like if (cond) { expr } else { () }

See What is return type of if statement? for details.

How to get Unit

To get an instance of type Unit you should use () literal:

if (zoom > 50) g.setPaintColour(ColourInt.white)
()

Unit value is the companion object of type Unit. It's not an instance of type Unit. Type of object Unit is Unit.type.

Do not use return in lambda

The result of lambda is the result of the last statement in lambda body, so you could just add result value (in this case literal ()) as the last line.

return in lambda will return from the surrounding method rather than from the lambda itself using exception (NonLocalReturnControl).

It's useful for java-style methods like this:

def firstNegative(seq: Seq[Int]): Option[Int] = {
  for {
    i <- seq
  } if (i < 0) return Some(i)

  return None
}

if (i < 0) return Some(i) here is lambda body. Equivalent code for this method:

def firstNegative(seq: Seq[Int]): Option[Int] = {
  seq.foreach{ i =>
    if (i < 0) return Some(i)
  }

  return None
}

OTHER TIPS

You should have a else clause :

   if (zoom > 50) g.setPaintColour(ColourInt.white) else ...

Benoit

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top