9

I am quite new to Scala and stumbled across following problem:

what is Scala equivalent of function's static variable ?

void foo()
{
    static int x = 5;
    x++;
    printf("%d", x);
}

EDIT:

What I want to achieve is a kind of function call counter - I want to check how many times my function has been executed and in the same time limit the visibility of this counter so that it can't be modified from outside.

tommyk
  • 3,187
  • 7
  • 39
  • 61
  • 2
    Could you describe why you make `x` static? Can it be accessed from outside of `foo`? Is `foo` maybe recursive? I am not very familiar with C++ and knowing your intention will make it easier to come up with a corresponding Scala code snippet. – Malte Schwerhoff Jan 07 '13 at 13:21
  • 2
    Pure functional programming avoids this kind of mutable variable cause it leads to a function that isn't "transparent". – Mik378 Jan 07 '13 at 13:25
  • 4
    C++ side: this is known as a local static, the variable is *global* in that only one instance exists throughout the program however its visibility (lexical scope) is restrained to the body of the function. This idiom may be used to implement singletons, for example. – Matthieu M. Jan 07 '13 at 13:26
  • possible duplicate of [In Scala, how would you declare static data inside a function?](http://stackoverflow.com/questions/1516087/in-scala-how-would-you-declare-static-data-inside-a-function) – Suma Apr 04 '15 at 15:30

3 Answers3

20

Here is a block of code that has similar effect:

scala> object f extends Function0[Unit] {
     |   var x = 0;
     |   def apply = {
     |     x = x + 1;
     |     println(x);
     |   }
     | }
defined module f

scala> f()
1

scala> f()
2

Although I must stress that this is a very bad practice since it kills referential transparency.

If you really need this behavior consider this:

type State = Int

def f(state: State) = {
 val newState = state + 1
 println(state);
 newState;
}
senia
  • 37,745
  • 4
  • 88
  • 129
pedrofurla
  • 12,763
  • 1
  • 38
  • 49
3

Scala has no equivalent to the local static variables of C++. In Scala, scoping rules are more consistent than in C++ or Java - what is defined within a block, goes out of scope when the block is exited. As others noted, a local static variable would be a side effect, which is not desirable in functional programming.

Scala, being a hybrid OO/functional language, makes it possible to write in imperative style, but prefers and encourages functional style (e.g. by making immutable collections the default choice). Local static variables, apart from representing a side effect per se, are absent in Java too, which is one more reason not to provide them in Scala.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
1

To get the equivalent of a C++ local static variable in Scala:

import scala.collection.parallel.mutable
import scala.reflect._
import scala.reflect.runtime.universe._

object StaticLocal {
  private val classes = new mutable.ParHashSet[String]
  private val variables = new mutable.ParHashMap[String, AnyVal]
}

import Numeric._

class StaticLocal[T <: AnyVal](value:T)(implicit tag: TypeTag[T], num: Numeric[T]){
  val name = this.getClass + "." + tag.toString() ;
  private var inited = false
  if (!inited) {
    inited = true

    if (!StaticLocal.classes.contains(name)) {
      StaticLocal.classes += name
      StaticLocal.variables += name -> value.asInstanceOf[AnyVal]
    }
  }
  def get():T = {StaticLocal.variables.get(name) match { case x:Some[Int] => (x.get).asInstanceOf[T] ; case None => throw new Exception("Not found:" + name) }}
  def set(value:AnyVal) { StaticLocal.variables.put(name, value)}
  def +(v:StaticLocal[T]):T = { num.plus(this.get, v.get)  }
  def +(v:T):T = { num.plus(this.get, v)  }
  def +=(v:T):Unit = { set(num.plus(this.get, v)) }
  def +=(v:StaticLocal[T]):Unit = { set(num.plus(this.get, v.get)) }

  override def toString() = { get.toString}
  implicit def StaticLocalWrapper(s: StaticLocal[T]):T = s.get
}

Then in the method:

def foo():Unit
{
  object x extends StaticLocal( 5 )
  x += 1
  println( x )
}        

This will work just like in c++, including when the method or owning class instance goes out of scope (albeit yet with a performance penalty). Not-thread-safe as it stands.