Anton
Anton

Reputation: 2341

Is it possible and how to have var that can only be set once?

Is there a native way to make sure that a variable can only be set once?

Currently, I am using this approach

class SetOnceVariable[T]
{
  private var value : T = _

  private var initialized = false

  def apply(_v : T = _) : T =
  {
    if (value != null && !initialized) {
      value = _v
      initialized = true
    }
    value
  }
}

class ClientInfo
{
  val userIP : SetOnceVariable[String] = new SetOnceVariable[String]
}

Upvotes: 11

Views: 941

Answers (5)

roterl
roterl

Reputation: 1883

you can use simple getter and setter:

class ClientInfo {
  private var _userIP: Option[String] = None
  def userIP: String = _userIP.get
  def userIP_=(value: String): Unit = {
    _userIP = _userIP.orElse(Option(value))
  }
}

val clientInfo = new ClientInfo()                       //> clientInfo : controllers.stackoverflow.ClientInfo controllers.stackoverflow$Clien
                                                        //| tInfo@4fccd51b
clientInfo.userIP = "first"
clientInfo.userIP                                       //> res0: String = first

clientInfo.userIP = "second"
clientInfo.userIP                                       //> res1: String = first

I prefer to use Option that the value directly to prevent nulls and NPE. You can of course add what ever logic you need in the setter.

Upvotes: 0

user5102379
user5102379

Reputation: 1512

Approach using lazy:

  class SetOnceVariable[T] {

    private var v: T = _
    private lazy val value: T = v

    def apply(_v: T = ???): T = {
      v = _v
      value
    }
  }

val info = new ClientInfo
println(info.userIP("IP")) // IP
println(info.userIP("IP2")) // IP
println(info.userIP("IP3")) // IP

To make it threadsafe you can use:

def apply(_v: T = ???): T =
  synchronized {
    v = _v
    value
  }

Upvotes: 1

Chris Martin
Chris Martin

Reputation: 30736

There's no such language construct, but I think I can clean up your code, at least.

class SetOnce[A](var toOption: Option[A] = None) {
    def set(a: A): Unit = if (toOption.isEmpty) toOption = Some(a)
    def get: A = toOption.get
}

Usage:

val x = new SetOnce[Int]
x.toOption // None

x.set(1)
x.get // 1

x.set(2)
x.get // 1

I omitted the null consideration because idiomatic Scala code tends to not use or consider null outside of Java compatibility. We mostly pretend that it doesn't exist.

Upvotes: 4

nitishagar
nitishagar

Reputation: 9403

You can try the following:

class varSingleton[A >: Null <: AnyRef] {
  private[this] var _a = null: A
  def :=(a: A) { if (_a eq null) _a = a else throw new IllegalStateException }
  def apply() = if (_a eq null) throw new IllegalStateException else _a
}

You can use this further like:

var singleVal = new varSingleton[Integer]
singleVal := 12
singleVal() // returns 12
singleVal := 13 //IllegalStateException

Upvotes: 0

John Cipponeri
John Cipponeri

Reputation: 892

You can create a constant variable by using a val. For instance:

val a = 0; // Cannot be changed
var b = 0; // Can be changed

See this answer for more details: https://stackoverflow.com/a/1792207/4380308

Edit:

A val can be declared and then initialized later as well.

val a;
a = 0;

Upvotes: 0

Related Questions