4

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?

1

4 Answers 4

7

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).

Sign up to request clarification or add additional context in comments.

3 Comments

Good answer. I was thinking about this, but I wasn't making the jump from def to val to make it work.
Pretty, if almost too clever.
As a follow-up that includes set-once variables assigned only in the init code, see this solution: stackoverflow.com/questions/4404024/…
5

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)
  }

}

Comments

1

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...

1 Comment

The problem here is that he doensn't wan't inited to be set, but it's value could be checked before the properly inicialization.
0

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
  }

}

2 Comments

But couldn't inited.set be called by another method?
You said "be sure no other method can set inited = false". There's no way for any method to set it to false with set in my example.

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.