tags:

views:

289

answers:

2

In many situations I find that I need to create long-living values inside a function's scope, and there is no need for this data to be at class/object scope.

For example,

object Example {

   def activeUsers = {
       val users = getUsersFromDB        // connects to the DB and runs a query

       users.filter(_.active)
   }

}

Above, the variable users is in the correct scope, but it will execute a DB query everytime the function activeUsers is called.

To avoid this, I could move the variable users outside the function's scope:

object Example {
   val users = getUsersFromDB        // connects to the DB and runs a query

   def activeUsers = {
       users.filter(_.active)
   }

}

But that makes it available to other functions as well.

Else, I could create a separate object to enclose the function:

object Example {

   object activeUsers {
       val users = getUsersFromDB        // connects to the DB and runs a query

       def apply() = {
           users.filter(_.active)
       }
   }

}

But this involves more boiler plate, use of another object and slight syntax oddities related to apply.

My questions are,

  • is there support for something like this at the language level?
  • if not, is there any standard technique that you use in this situation?
+14  A: 

Another option would be using a closure:

object Example {
   val activeUsers = {
       val users = getUsersFromDB
       () => users.filter(_.active)
   }
}

Explanation

activeUsers is a variable of type Function1[Unit, ...your filter result type...] (or we can write this type as (Unit => ...your filter result type...), which is the same), that is this variable stores a function. Thus you may use it later in a way indistinguishable from function, like activeUsers()

We initialize this variable with a block of code where we declare variable users and use it inside an anonymous function () => users.filter(_.active), hence it is a closure (as it has a bound variable users).

As a result, we achieve your goals: (1) activeUsers looks like a method; (2) users is calculated once; and (3) filter works on every call.

Alexander Azarov
Spot on. You might want to explain what is happening in there, and why does it work.
Daniel
Added the explanation
Alexander Azarov
Thanks for the explanation. I am still hoping to find a more sugary syntax akin to C's "static" variables.
HRJ
+2  A: 

Extending FunctionXX is another way of achieving the goal; it might have an advantage of providing better documentation. Both parameter types and return value type are visible on the first line of the declaration:

val activeUser = new Function0[List[String]] {
  val users = getUsersFromDB
  def apply = users filter (_.active)
}
Walter Chang