Gamasutra.com Features - The Transition to Concurrency
It's free to join Gamasutra!|Have a question? Want to know who runs this site? Here you go.|Targeting the game development market with your product or service? Get info on advertising here.||For altering your contact information or changing email subscription preferences.
Registered members can log in here.Back to the home page.

Search articles, jobs, buyers guide, and more.

Gamasutra
April 5, 2007

The Transition to Concurrency

arrowrightPage One
arrowrightPage Two
arrowrightPage Three
arrowrightPage Four

Printer Friendly Version




Latest Letters to the Editor:
Perpetual Layoffs by Alexander Brandon [09.21.2007]

Casual friendliness in MMO's by Colby Poulson [09.20.2007]

Scrum deals and 'What is Scrum?' by Tom Plunket [08.29.2007]


[Submit Letter]

[View All...]
  


The Transition to Concurrency


Avoid State: Immutable Types

The key to functional programming, which happens to be a very good policy to enforce in general, is avoiding state. Mutable state, that is. Mutable state in software is like moving parts in hardware. It makes your code more vulnerable to external conditions, and it makes it harder to maintain.

To people with no experience with functional programming languages, this can be hard to grasp. Or rather, it can be hard to realize that there is a difference (it was for me, anyway).

In pure functional programs everything is immutable. This basically means that every variable isn't - it's a constant. There is no way to declare a C++ type immutable but what you can do is declare a variable const, which basically means that the type of the given variable is an immutable version of the type specified.

A Simple Example

Consider this simple color class:

class Color
{
private:
	double red_;
	double green_;
	double blue_;

public:
	Color(double red, double green, double blue) : 
red_(red), green_(green), blue_(blue) {} double GetRed() const { return red_; } double GetGreen() const { return green_; } double GetBlue() const { return blue_; } double SetRed(double red) { red_ = red; } double SetGreen(double green) { green_ = green; } double SetBlue(double blue) { blue_ = blue; } void Multiply(double factor) { red_ *= factor; green_ *= factor; blue_ *= factor; } };

Fairly common style, I would say. Nice encapsulation even though you can read and write all private fields. But if you wanted to, you could easily introduce a contract by adding checks in the accessors and the multiply method.

To make this class immutable, we could change it like this:

class Color
{
private:
	double const red_;
	double const green_;
	double const blue_;

public:
	Color(double red, double green, double blue) : 
red_(red), green_(green), blue_(blue) {} double GetRed() const { return red_; } double GetGreen() const { return green_; } double GetBlue() const { return blue_; } Color Multiply(double factor) const { return Color(red_ * factor, green_ * factor, blue_ * factor); } private: Color& operator = (Color const& a) {} };

At first glance, the difference may not seem important. The Set* methods are gone and the Multiply method has changed a little. No biggie. But the real change is in the fact that this class is now immutable.

Once instantiated, you have no way to change the contents of the object. You can multiply the color by a factor, but this gives you a new instance. Also, the assignment operator has been declared private which means that it cannot be invoked from the outside, not even implicitly. This makes the class thread-safe even though it contains no semaphores.

You are forced to use it in a way that will work in multiple threads and you can be sure that it will never produce deadlocks or become corrupted by simultaneous access. Introducing a contract in this version means checking the invariant in the constructor - that's all.




join | contact us | advertise | write | my profile
news | features | companies | jobs | resumes | education | product guide | projects | store



Copyright © 2006 CMP Media LLC

privacy policy
| terms of service