Michał Kosmulski
Michał Kosmulski

Reputation: 10020

Why are SessionVars in Lift implemented using singletons?

One typical way of managing state in Lift is to create a singleton object extending SessionVar, like in this example taken from the documentation:

object MySnippetCompanion {
  object mySessionVar extends SessionVar[String]("hello")
}

The case for using SessionVars is clear and I've been using them in practice as needed. I also roughly understand how they work inside.

Still, I can't help but wonder why the mechanism for "session variables", which are clearly associated with the current session (usually just one out of many sessions in the system), was designed to be used via a singleton? This goes so against my intuition that at first glance I was tempted to believe that Lift was somehow able to override Scala's language features and to make object mean something different that in regular Scala.

Even though I now understand how it works, I can't grasp the rationale for such a design, which, at least for me, breaks the rule of least astonishment. Can someone point out any advantages or perhaps explain why such a design decision could have been made?

Upvotes: 1

Views: 152

Answers (2)

nafg
nafg

Reputation: 2534

The reason you have to use the object keyword is that object is unique in that it defines both a value and a class. This allows Lift to call getClass to get a name that uniquely identifies this SessionVar vs. any other one, which Lift needs in order to serialize and deserialize every piece of session state in the right place(s). Furthermore if the SessionVar is in a class that has two instances (for instance a snippet rendered in two tabs), they will both refer to the same piece of session state. (The flip side of the coin is that the same SessionVar instance can be referenced by two different sessions and mean the right thing to each.) Actually at times this is insufficient --- for instance, if you define a SessionVar in a trait, and have two different classes that inherit the trait, but you need them two have two different values. The solution in that case is to override the def for the "name salt", which is combined with getClass to identify the SessionVar.

Upvotes: 2

gzm0
gzm0

Reputation: 14842

Session variables in Lift use Scala's DynamicVariable. Basically they allow you to statically reference a variable in a code-block and then later on call the code and substitute a value:

import scala.util.DynamicVariable

val x = new DynamicVariable(1)

def printIt() {
  println(x.value)
}

printIt()
//> 1

x.withValue(2)(printIt())
//> 2

So each time a request is handled, the scope of these dynamic variables is changed to the current session, completely hiding the state change of the current session to you as a programmer.

The other option would be to pass around a "sessionID" object which you would have to use when you want to access session specific data. Not really handy.

Upvotes: 5

Related Questions