A strong feature of Scala is the embracing of both Functional Programming (FP) and Object Orientation (OO). This was a very deliberate and early design decision of Scala in recognition of the strengths of both approaches over the decades. I hope to show you that utilising both approaches to developing software can work together.
Over the past two years of using Scala on a daily basis I’ve found myself adopting a predominantly FP approach to development, while embracing true OO in the form of Akka’s actors. What this boils down to is side-effect-free programming with functions focused on one purpose. Where state is required to be maintained, typically for IO style scenarios, then actors come to the rescue. Within those actors if there are more than 2 state transitions then I find myself using Akka’s FSM where upon it maintains the state through transitions. As a consequence, there are very few “var" declarations in my code, but I don’t get hung up on their usage where the code becomes clearer or there is a performance advantage in some critical section of code.
I can’t even remember the last time I used a lock of some type...
Thus my actor code looks something like this:
object SomeActor {
def props(): Props =
...
// My actor’s other pure functions,
// perhaps forming the bulk of code.
// The functions are typically private
// to the package and therefore
// available for tests within the
// same package.
}
class SomeActor extends Actor {
override def receive: Receive =
...
// Functions that break down the
// receive handling calling upon the
// pure functions of the companion and
// possibly other traits
}
What I find is that as I expand the companion object with pure functions, patterns of behaviour emerge and its functions are factored out into other traits which of course become re-usable and remain highly testable. Sometimes I form these behavioural abstractions ahead of creating the companion object, but more often than not it is the other way round. I’m big on continuous re-factoring and spend a lot of time attempting to get the functional abstractions right. This can mean that the functions are often re-written once the behavioural patterns emerge.
So why then is the above representative of OO? Actors permit only message passing and are completely opaque to the outside of their instance. This is one of Alan Kay’s very early requirements of OO. Actors combined with Scala also mostly fit his following requirements (taken from http://c2.com/cgi/wiki?AlanKaysDefinitionOfObjectOriented):
- Everything is an object.
- Objects communicate by sending and receiving messages (in terms of objects).
- Objects have their own memory (in terms of objects).
- Every object is an instance of a class (which must be an object).
- The class holds the shared behavior for its instances (in the form of objects in a program list).
- To eval a program list, control is passed to the first object and the remainder is treated as its message.
Point 3 is a weak point of the JVM and one should be careful about message payloads remaining immutable, but at least with Scala, immutability is the default way of coding. It’d be great if actors themselves had their own address space. However this has never raised itself as a problem in my world.
Scala is one of the few languages that marries the world of FP and OO and thus does not need to “throw the baby out with the bathwater”. Many other languages force you to make a choice. That said, just like most marriages, there’s always the dominant party making the most sense, and that’d be FP!
2 comments:
OCaml and F# come to mind as languages that support the two paradigms.
Thanks Robert. I've relaxed my statement in that regard.
Post a Comment