10

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.

4
  • 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. Commented Jan 7, 2013 at 13:21
  • 2
    Pure functional programming avoids this kind of mutable variable cause it leads to a function that isn't "transparent". Commented Jan 7, 2013 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. Commented Jan 7, 2013 at 13:26
  • possible duplicate of In Scala, how would you declare static data inside a function? Commented Apr 4, 2015 at 15:30

3 Answers 3

21

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;
}
Sign up to request clarification or add additional context in comments.

2 Comments

This (the first example) is in fact more like a C++ functor, but it indeed behaves as if f() had a local static variable.
This doesn't necessarily have to kill referential transparency. Memoization comes to mind.
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.

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.