AlessandroEmm
AlessandroEmm

Reputation: 698

Do something only once, without state

I have the following situation:

Upon initialitation (actually first receive) of a socket I want to check something in the handshake (TLS), this has to be only checked upon connection initialization and not on every further receive.

Currently I have an odd:

   // this is happening outer scope
   var somethingThatGetsComputedinInit = 0

   def receive {
      if (init) {
        somethingThatGetsComputedinInit = doinitstuff(StuffIOnlyGetInitially)
        init = false
      }
    }

Although it would work, this smells so imperative and ugly. What would be a purely functional solution to this?

Upvotes: 4

Views: 2425

Answers (5)

galbarm
galbarm

Reputation: 2543

You can also consider using var with function callback and update the var to do nothing after the first time:

   var firstTimeInit = StuffIOnlyGetInitially => doinitstuff(StuffIOnlyGetInitially)

   // this is happening outer scope
   var somethingThatGetsComputedinInit = 0

   def receive {
        somethingThatGetsComputedinInit = firstTimeInit(StuffIOnlyGetInitially)
        firstTimeInit = StuffIOnlyGetInitially => ()
    }

Upvotes: 0

drstevens
drstevens

Reputation: 2913

In your specific example, since you are using actors, you actually can swap out its implementation to model a state machine using "context.become and context.unbecome". There is an abstraction layer, Akka FSM, on top of this which provides a nicer syntax for doing exactly this type of thing.

Example partially lifted from the Akka FSM docs:

sealed trait State
case object Initializing extends State
case object Initialized extends State

class Socket extends Actor with FSM[State, Option[Client]] {

  startWith(Initializing, None)

  when(Initializing) {
    case Event(msg: Connect, _) => createClient(msg).fold(stay) {
      client => 
        //Do more stuff
        goto(Initialized) using Some(client)
    }
  }

  when(Initialized) {
    case Event(msg: Receive, data@Some(client)) => 
      //Do more stuff using client
      stay using data
  }

  initialize()

}

Upvotes: 4

Przemek Pokrywka
Przemek Pokrywka

Reputation: 2249

Sounds like good use-case for Scala "lazy val".

lazy val somethingThatGetsComputedinInit = doinitstuff()

You get guarantee that the val gets initialized only once, at the time of first use. I don't know where that is in your code, if it's the proper place, but if not, you could just refer to the val inside "receive" to force the initialization.

Upvotes: 0

whaley
whaley

Reputation: 16265

This is a case where you want to make use of the lazy val modifier in scala. This is suggested in Twitter's Effective Scala. Consider the following edits to the example in your question.

class Foo {
    def doinitstuff() : Int = {
        println("I'm only going to be called once")
        42
    }

    lazy val somethingThatGetsComputedinInit = doinitstuff()

    def receive {
        println(somethingThatGetsComputedinInit)
    }
}

and a client of an instance of Foo calling receive multiple times would output the following:

 val foo = new Foo                               //> foo  : worksheet.Foo = worksheet.Foo@5853c95f
  foo.receive                                     //> I'm only going to be called once
                                                  //| 42

  foo.receive                                     //> 42
  foo.receive                                     //> 42

Upvotes: 12

Victor
Victor

Reputation: 3978

Excellent question.

You should definitely read the state pattern.

There is an example, extracted from Eric Gamma Desing patterns book* that works, like you, with TCP connections. It is not functional programming but could serve you as a guide.

*A reference guide for design pattern, hoverer i do not recommend this book, instead i strong encourages you to read Head First : Design pattern that has a more powerful didactic tools for inviting you to thing with design principles, far more important than patterns (and paradimgs).

Hope it helps!

Upvotes: 1

Related Questions