views:

66

answers:

3

I am looking at functional programming and struggling with one point.. How do I do the following without mutable state?

Imagine I have a server.. and clients try to connect.. and each client gives the server a number and gets told the current total.

Now without mutable state the server can't keep a total... so I am thinking each client is really creating a new server containing a new total.. or a new server holding the entry and referencing the old server so the total can be calculated.

BUT.. how do the client's find the server? Someone has to hold onto the current server instance.. so they have a mutable variable 'server'.

No matter what I do.. I always end up with a mutable variable a the higher scope.

Thoughts?

+5  A: 

The scenario you describe could be implemented like this (pseudocode):

let keepTrackOfTotal(total) =
    let conn = waitForConnection()
    let x = readIntFrom(conn)
    let newTotal = total + x
    writeIntTo(conn, newTotal)
    keepTrackOfTotal(newTotal)

let main() = keepTrackOfTotal(0)

Here we use recursion to get an infinite loop that keeps track of the total, without mutable variables.

sepp2k
I can see how this would work with multiple sequential clients. Would this work in a multicore parallel system? Does this force it to be sequential?
Nigel Thorne
It does force it to be sequential, because it can only handle one connection at a time. The problem then with multicore is that you might refuse a connection(s). Often you have some kind of mechanism to deal with that. Erlang's mechanism is to have all your clients pass your server a message which gets placed in a queue for processing. That's not the only way, though I'm not too familiar with others.
Jon Smock
+3  A: 

At least in Erlang the way it's done is that the process itself has a name.

So while the server loop is constantly starting new versions of itself (by calling the same function at the end of the call, like in sepp2k's excellent pseudocode) and feeding in the sum as a parameter, all your clients are contacting that process by name, so they can still find it.

Jon Smock
A: 

Something like this (on C++). We have static pointer server, each instance of server object is immutable

#include <pthread.h>
#include <iostream>
#include <stdlib.h>
#include <memory>

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;

class Server
{
public:
    Server(int n) : m_n(n){}
    static void Add(int n)
    {        
        pthread_mutex_lock( &mutex1 );
        std::auto_ptr<const Server> srv(getInstance());
        server = new Server(srv->m_n + n);
        pthread_mutex_unlock( &mutex1 );
    }
    static int GetTotal()
    {
        std::auto_ptr<const Server> srv(getInstance());
        return srv->m_n;
    }

private:

    static const Server* getInstance()
    {
        if (server == NULL)
            server = new Server(0);

        return new Server(server->m_n);
    }
    static volatile const Server* server;
    int const m_n;
};
volatile const Server* Server::server = NULL;

Every call of the getInstance() returns of the immutable Server object. You can call GetTotal() method when another thread work in Add method.

Andrew
You didn't really get around mutability here though. You just moved it from having a mutable `total` variable to having a mutable `server` variable.
sepp2k