Concurrent Programming Lessons, and some abstract thought 1
Taking a break from my self serving blogging about my machine geekery, I’d like to jot down my thoughts on building a concurrent language that merges some powerful concepts from other existing languages. Based on lessons from Erlang, Ruby, and JavaScript I think it is possible to approach a working model for how to do safe concurrency in an object oriented manner.
First, let’s examine some concepts from Erlang, or Concurrency Oriented Programming:
- The world around us is concurrent
- Each cogniscent being maintains their own state
- Exchange of ideas is performed by passing messages
- By responding to messages, each cogniscent being may change their state
Based on these operations, Erlang makes a few restrictions. Variables are write-once (i.e. immutable once set). Because of this, Erlang does not need locks, mutexes, semaphores, or other fancy concurrency control mechanisms the popular languages use. All reads will be the same, regardless of timing issues. Processes are first class citizens, and no memory is shared between processes. Again, the same evils apply. If information is passed from one process to another, it is done by sending messages. The approach echoes observations smarter people than myself have seen in using SAX vs. DOM for XML parsing. The event (message) based architecture of SAX was less memory demanding and easier to maintain throughput in highly concurrent systems (i.e. web servers) than the DOM alternative. There’s a few more things in here that deal with reliability such as the VM’s ability to monitor and restart processes that fail. The end result are programs that scale easily with the processing nodes available, both local CPU cores and remote machines.
Next, let’s examine some concepts from Ruby, or Object Oriented Programming:
- The world around us consist of things
- Things can act on other things, or can be the recipient of actions
- Each thing should maintain its internal state
- Things act on other things by sending messages (i.e. calling methods)
Based on this set of basic rules, there is a fair amount of overlap between the highly concurrent Erlang concepts and the object oriented view of Ruby (or Java, or C# if you prefer). In practice there are a few different types of things. First, there are things (objects) that cannot act on their own (i.e. value objects like color, money, or dates) but will respond accordingly when acted on by others. These value objects never change state and are completely passive. Next there are objects that represent the current state of the world. These business objects, as some call them, maintain their own state and respond to messages from other objects. In some cases, the business objects will act on other business objects. Finally, there are things that act, or service objects. A service objects are a little different than the physical representations of the other two types of objects, but they take care of complex logic, workflow, etc.
Finally, let’s examine JavaScript, or Prototype Based Programming:
- There are no object descriptions (classes), only objects
- Objects can send or respond to messages (i.e. calling methods)
- Objects should maintain their internal state
So there is some overlap here as well. The major difference between prototype languages and object languages is the lack of a class. In essence, instead of defining how an object should look and behave using a class, you copy an existing object prototype. In the copy process you can extend the prototype by adding methods (new message receivers), properties, or whatever you like. You can also simply use the object as it is. There is a side effect here, that is the system tends to have fewer objects overall compared to your object oriented system. That helps with pesky matters like garbage collection. However, the objects tend to be a bit more powerful.
Now, some personal observations based on working with these languages:
- I come from an object oriented background, it makes sense to me so it’s hard to make the mental shift to the other programming approaches.
- There is a fair amount of overlap in the concepts, to the point where we can start formulating how to merge them.
- Defining a class for an object that will have only one instance seems a bit excessive. The system has to keep the definition of the object and the object resident in memory. Perhaps the prototype approach can help reign that in.
- Tying a process to an object gives us the concurrency of Erlang and the familiarity of objects. Essentially, the messages are methods and each object manages itself in its own process. Garbage collection can be much quicker since the collector can be optimized for one process’s data.
- Straight value objects don’t necessarily need their own process, they can run within the process (object) that uses them.
I’ve also identified a few challenges with the process/object approach as well. Processes will have to be monitored to see if they are still in use. A special garbage collector would need to be written for that purpose. The Erlang concept of a write-once variable matches the mathematical ideal well. For example, X=X+1 is a mathematical impossibility but a common programming concept in many languages. Yet, objects need to vary their state over time. Special distinction needs to be made to differentiate state that can change vs. state that cannot change. In some ways the concept of a Map for maintaining the internal state of an object is a natural approach. It might be how Erlang programmers maintain state in their processes.
There are a few things that I am concerned with, no matter what the language is or how concurrency is performed:
- Security. There’s bad people out there wanting to do bad things. Unfortunately, most security models are more of a pain to work with and consequently don’t get used.
- Internationalization. We live on a planet with many languages and cultures. At the very least UTF should be the default internal representation of strings. This is still a field the industry is trying to figure out.
- Robustness. Error handling has to be given special attention. If you get it right, you will help people create software that won’t easily break. If you get it wrong, you will help people create monstrocities that break more easily.
- Testability. Anyone who has done unit testing seriously has learned that the design of the code affects how easy it is to test. The easier it is to test, the easier it is to catch bugs, and the less likely people will complain about writing unit tests.
- Scalability. The platform should make it easier to take advantage of new features like multicore processors and remote machines. Ideally, the software performance should scale along with the hardware. I hate jumping through hoops to do what should really be done in the platform.
These are just random thoughts. Please shoot holes in them. I know I’ll have to figure out a lot of details to make something like that work.

You might take a look at the Reia programming language, which (simplifying, and possibly making a hash of the details) makes each object an Erlang process, and also has a more familiar syntax.
Erlang often stores state in a receive loop in a process. Which, at times, to me seems like a bit of a messy hack just to pretend you don’t really have state. It’s far easier if you can just do things explicitly.