[erlang-questions] Deriving records from one another?

Jachym Holecek <>
Mon Jun 23 16:52:55 CEST 2014


# Roger Lipscombe 2014-06-23:
> I'm probably thinking too OO by calling it "deriving", but here's the problem:
> 
> OTP handlers (gen_server, etc.) take a State parameter. You can stick
> anything in here, but generally I've been using a #state record, and
> keeping a bunch of values in it.

Sure, that's how everybody uses them all the time.

> Now I'd like to actually start representing *state* with the State[1].
> That is, I'd like to be able to match on #init, #ready,
> #expecting_key, #whatever records.

Why? What actual real-world problem are you trying to solve, and why
does this approach look like a plausible solution to it? Why do you
think gen_fsm is not adequate for describing what looks every bit
like a state machine?

> This will hopefully make the code easier to read,

I quite doubt it will, to be honest.

> and means that my record doesn't have to contain
> fields for stuff that's not relevant in the given state.
>
> However, some of the fields *are* shared between states, so my
> question is (in OO terms) how do I derive record types from
> each-other?
> 
> I've thought about using a tuple: {Shared, State} when Shared ::
> #shared{}, State :: #init{} | #etc{}
> That might be hard to read in matches, though, maybe.
> 
> I've thought about using a container record:
> -record(state { shared :: #shared{}, inner :: #init{} | #etc{} }).
> 
> Are there any good solutions[2] to this problem?

Can't think of anything that wouldn't read like a horror story.

> Or are there better ways to do what I'm trying to do?

There may be a way to avoid doing what you're trying to do. :-) My
guess is you're uncomfortable with what you've got now because your
gen_server/gen_fsm ended up having way too much functionality in it
(Ulf's "Death by accidental complexity" comes to mind) and starts
looking too messy.

Quite often one can break things into a toplevel gen_server/gen_fsm
with a bunch of private small processes running underneath it via
proc_lib:spawn_link/X or whatever -- just plain simple processes.

These workers can do all sorts of utility control loops and regulators,
whilst the parent coordinates the whole show, takes highlevel decisions
and maybe also serves as public point of contact to this particular
subsystem/resource.

(This is really just a particular example of "designing more concurrently",
which clearly is a pretty vague thing to say and thus unhelpful. ;-)

Worked nicely for me every time... but then I haven't seen your project
specification or the code in question.

BR,
	-- Jachym



More information about the erlang-questions mailing list