Given this situation:
object ResourceManager {
private var inited = false
def init(config: Config) {
if (inited)
throw new IllegalStateException
// do initialization
inited = true
}
}
Is there any way that I could make inited
somehow “private to init()”, such that I can be sure that no other method in this class will ever be able to set inited = false
?
Taken from In Scala, how would you declare static data inside a function?. Don’t use a method but a function object:
val init = { // or lazy val
var inited = false
(config: Config) => {
if (inited)
throw new IllegalStateException
inited = true
}
}
During initialisation of the outer scope (in case of val
) or first access (lazy val
), the body of the variable is executed. Thus, inited
is set to false
. The last expression is an anonymous function which is then assigned to init
. Every further access to init
will then execute this anonymous function.
Note that it does not behave exactly like a method. I.e. it is perfectly valid to call it without arguments. It will then behave like a method with trailing underscore method _
, which means that it will just return the anonymous function without complaining.
If for some reason or another, you actually need method behaviour, you could make it a private val _init = ...
and call it from public def init(config: Config) = _init(config)
.
The below absolutely counts as way more trouble that it's worth, but does satisfy the specs. There's no way to do so otherwise
object ResourceManager {
private object foo {
var inited = false
def doInit(config:Config){
if (inited)
throw new IllegalStateException
// do initialization
inited = true
}
}
def inner(config: Config) {
foo.doInit(config)
}
}
It would be easier to create a "trapdoor" object which can only go from false to true:
object ResourceManager {
object inited {
private var done = false
def apply() = done
def set = done = true
}
def init(config: Int) {
if (inited())
throw new IllegalStateException
// do initialization
inited.set
}
}
If all you want to do is make sure that init
is called once, do something like this:
lazy val inited = {
// do the initialization
true
}
def init = inited
that way the initialization code will only run once, however many times you run init
, and inited
cannot get another value since it's a val
. The only downside is that as soon as inited
is queried for its value the initialization will run...