4

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?

4
  • Is somethingThatGetsComputedinInit persistent between calls? I that case you could use somethingThatGetsComputedinInit == 0 Commented Oct 19, 2013 at 18:25
  • I don't think "functional programming" has to do anything here. You either store the state on the server side as you do it now in init or you make the client send you whether this is his first packet or not. This seems not too safe as you will rely on the client. You could Send back to the client some computed value which he would then have to resend to you (like a token) and if that value was present you'd know it's not his first time but then you'd need an algorithm which wouldn't require you to store that token on the server side as it would result in the same code you have now. Commented Oct 19, 2013 at 18:30
  • @Bittenus somethingThatGetsComputedinInit is defined outer scope and just initialized in the init block and used after that (after the Initial call). Commented Oct 19, 2013 at 18:52
  • @MateuszDymczyk I see your point, but as my "client" is a common browser, it will be quite hard to introduce some special computation :-) Commented Oct 19, 2013 at 18:58

5 Answers 5

12

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 
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you! Looks a lot like the "silver bullet" - only problem I have that doinitstuff() can potentially have side-effects - when the init doesn't work out, in my case if it isn't capable of TLS 1.1 it has to be terminated. But thats probably just how it has to be. Will try this anyway.
can I somehow pass something to doinitstuff() ? I added the parameter "StuffIOnlyGetInitially" that I pass to doinitstuff()
supposedly can be done with anon function -> will try that :-)
sorry my question, but only for interest... this "val" modifier, has the same functionality that has the "static" modifier in C employed to variables defined inside a block within a function that make then persist the original once initialized??
@Victor a variable/field with the val modifier means that variable/field in question may only be assigned to once.
|
4

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

7 Comments

I see, become allows me to swap the receive implementation, pretty cool - state pattern made easy. :-) will give it a try, thanks!
I'd recommend using Akka FSM instead of using become directly, but that's just me.
Presumably the "Uninitialized" in startWith should be "Initialized". I tried to change it, but StackOverflow amazingly thinks that a 3-character change cannot possibly be important, and won't allow it. Might be clearer to use "Ready" anyway.
@AlessandroEmm Use FSM and put it in the type reserved for data. I've never used become directly but I'm assuming there is a way. In the example above, this would replace, Option[String], which was an attempt at demonstrating this. I believe the API uses the term state data or maybe just data now.
@AlessandroEmm See doc.akka.io/docs/akka/snapshot/scala/…. You should be able to do something like def happy(state: Client): Receive = { instead of def happy: Receive = {. I updated my FSM example above to pass clients instead of strings.
|
1

You should definitely read the state pattern.

There is an example, extracted from Eric Gamma Design 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, however 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 paradigms).

2 Comments

Thank you! this would be a very good solution, if i'd be doing low-level socket handling. But since I use Akka IO I'm not as flexible with swapping the whole class (as far as I understand) as this would impose swapping the actor, which would make the code even more complicated.
Ohh, i see. I don't know Akka and Scala. Well there are a lot of rich answer above, hope you can overcome this situation!.
0

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.

Comments

0

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.