Apr 5 2009

Parameterized Modules in Erlang

There is an erlang syntax that is beloved by OO converts to the language,  the parametrized module.  Here is why.

> Obj = param_example:new("Tony").
> Obj:name().
"Tony"

This Syntax makes an OO guy feel cozy.  And taking a look at the implementation of our module, we see the the implied variable is defined on the module definition.

-module(param_example, [Name]).
-export([get_name/0, set_name/1]).

get_name() -> Name.

There is a caveat.  If a module is parametrized, all functions are parametrized.  You cannot use non-parametrized functions to wrap your parametrized function, like this.

> Obj = param_example:new("Tony").
> ListOfNames = param_example:new_from_list(["Tom", "Dick", "Harry"]).

In fact, there’s some magic, functions actually have an arity of one more than you think. Actually, an extra parameter for each module parameter. In addition, these are constant, like all erlang variables. Since you don’t have access to a recursive call stack, you can’t change them.

However you can use a separate module to front- end the parametrized calls. And “mutating” calls can return new instances with new parameters.

So when Is it a good thing and when do you not want to use it?  I like the idea of using parametrized devices to wrap a bunch of data I’m going to be passing around but still has some functionality that needs to be called.

The scenario I didn’t find it useful for is having several processes that I can call without having a reference.  More concretely, I need to have rooms addressable via names of some other soft reference.  And their variables need to be modifiable. I abused named gen_server services for this.

-module(named_example).
-behaviour(gen_server).
-export([start_link/2, get_description/1, handle_call/3,init/1]).
-record(room, {name, description}).

server_name(Name) -> list_to_atom( lists:concat([ ?MODULE, "_", Name])).

start_link(Name, Description) ->
  gen_server:start_link({local, server_name(Name)}, ?MODULE, #room{name=Name, description=Description}, []).

get_description(Name) ->
  get_description:call(server_name(Name), description.

handle_call(description, _From, State) ->
  {reply, State#room.description, State}.

So, there are two ways of dealing with a collection of processes that are cleaner (don’t use the raw message send) than just passing around a Pid.  They do different things, but might could be used in combination.  I’m just not sure how, yet.

Oh, hey. If you have a better solution, please post a comment.


Dec 24 2008

Project: MUD

I kind of mentioned this project at the tail end of the big py country post. I’ve been spending some time writing a rudimentary MUD in Erlang. Why? MUDs are fun. I want to know if Erlang is a fit for any future SEP projects. And I’m interested in what it would take to do the same thing on the .NET platform.

So, what do I mean by ‘rudimentary’ MUD? I want to connect via telnet. I want to issue commands. I want to move from room to room. I want to create rooms. I want to create items. I want to meet others waking around the mud. I want to run my mud across a cluster of servers. But, at this point scripting and combat aren’t in scope.

While I’ve made progress, Holidays happen and it will probably take a few weeks longer than the one week I was originally planning. I’ve got my telnet and command parser. I’m logging in and storing my users in the world. And that’s where I am right now.  It’s not just to holidays, it’s also learning a new language and it’s libraries.  I’ve had to fight with the dictionary for a while, then there’s some missing commas that keep cropping up.

I’m still trying to figure out the finer points of OTP, which may cause a rewrite of my telnet service.

Once I’m done, I’ll be putting together a more complete post on the project and start using this as a referance for a .NET implementation. Now, the .NET implementation may only be a roadmap and a short talk comparing the two platforms. Either way, this should be fun.