scalaparameterspass-by-referencepass-by-name

Determine by parameter which member to change


Following Scala code gives a compile error stating I cannot assign to a val:

Simplified example:

class State {
  val a = 1
  val b = 2

  def compute( res: =>Int, add : Int ): Unit = {
    res = add + 123456
  }

  compute(a,b)
  compute(b,a)
}

Example closer to my real use:

class Editor {
  var str:String = ""
  var cursor:Int = 0

  case class UndoState(str:String, cursor:Int)

  var undoState = Seq[UndoState]()
  var redoState = Seq[UndoState]()

  def undo(): Unit = if (undoState.nonEmpty) {
    redoState = UndoState(str,cursor) +: redoState
    str = undoState.head.str
    cursor = undoState.head.cursor
    undoState = undoState.tail
  }

  def redo(): Unit = if (redoState.nonEmpty) {
    undoState = UndoState(str,cursor) +: undoState
    str = redoState.head.str
    cursor = redoState.head.cursor
    redoState = redoState.tail
  }
}

As both undo / redo are very similar, I would like to extract the common code into a function, which I wanted to pass source / target pairs as redoState/undoState and the other way around.

Is there some way how to tell where should a function store something? (In C++ I would pass a pointer to member in this situation).


Solution

  • Use the return value:

    def compute( add : Int ): Int = {
      add + 123456
    }
    
    val a = compute(b)
    val b = compute(a)
    

    pass by reference as you would do it in C++ can't be done in Scala and is generally not what you want to do either. However, you can pass a container that contains a reference to a mutable field:

    class Box(var value: Int)
    
    def compute( box: Box, add : Box): Unit = {
      box.value = add.value + 123456
    }
    
    val a = new Box(1)
    val b = new Box(2)
    compute(a, b)
    compute(b, a)
    

    Or (a slight variation) make compute member of Box:

    class Box(var value: Int) {
      def compute(add: Box): Unit = {
        value = add.value + 123456
      }
    }
    
    val a = new Box(1)
    val b = new Box(2)
    a.compute(b)
    b.compute(a)