Sometimes I miss destructively updating local variables

RCB rcbeerman@REDACTED
Fri Jul 7 07:10:12 CEST 2006

Maybe something like this...

-record(vrec, {x1, y1, x2, y2}).  % (or just use a 'raw' tuple if the
x1,.. set is static)

make_line_rec([{Tag, Ofs, Len} | T], B, Acc, V)
	when Tag == x1; Tag == y1; Tag == x2; Tag == y2 ->
	make_line_rec(T, B, Acc, parse_units(Tag, V, B, Ofs, Len));
make_line_rec([{Tag, _, _} = Attr|T], B, Acc, V) ->
	case is_attr(Tag) of
		true ->
			make_line_rec(T, B, [get_attr(Attr, B)|Acc], V);
		false ->
			make_line_rec(T, B, Acc, V)
make_line_rec([], _, Acc, V) ->
	{line, Acc, V#vrec.x1, V#vrec.y1, V#vrec.x2, V#vrec.y2}.

parse_units(Tag, V, B, Ofs, Len) ->
       % create data to assign to one of the x1... vars
       set_vrec(Tag, V, Data).

set_vrec(x1, V, Data) -> V#vrec{x1 = Data};
set_vrec(x2, V, Data) -> V#vrec{x2 = Data};

Of course, I'm pushing some of the density down beyond parse_units,
but this seems to be what I typically do.   Isolating the X1,... vars
into a single #vrec{} also makes the function a little easier to
modify if you ever need to add extra elements.

My .02....

On 7/6/06, James Hague <james.hague@REDACTED> wrote:
> Often I find myself writing a function that's just a case statement
> where each branch ends with a tail-recursive call.  Here's an example
> pulled from working code:
> make_line_rec([{Tag,Ofs,Len}=Attr|T], B, Acc, X1, Y1, X2, Y2) ->
>    case Tag of
>       x1 -> make_line_rec(T, B, Acc, parse_units(B, Ofs, Len), Y1, X2, Y2);
>       y1 -> make_line_rec(T, B, Acc, X1, parse_units(B, Ofs, Len), X2, Y2);
>       x2 -> make_line_rec(T, B, Acc, X1, Y1, parse_units(B, Ofs, Len), Y2);
>       y2 -> make_line_rec(T, B, Acc, X1, Y1, X2, parse_units(B, Ofs, Len));
>       _ ->
>          case is_attr(Tag) of
>             true  -> make_line_rec(T, B, [get_attr(Attr, B)|Acc], X1,
> Y1, X2, Y2);
>             false -> make_line_rec(T, B, Acc, X1, Y1, X2, Y2)
>          end
>    end;
> make_line_rec([], _, Acc, X1, Y1, X2, Y2) -> {line, Acc, X1, Y1, X2, Y2}.
> What bugs me is having to list all the variables in the make_line_rec
> call.  In reality, this function is just a while loop, and each time
> through the loop one of a set of local variables (Acc, X1, Y1, X2, Y2)
> is updated.  Before any functional purists jump on me, this is EXACTLY
> how the generated BEAM code works.  Those variables live in registers,
> and each make_line_rec "call" destructively updates one of those
> values, then jumps to the start of the function.
> In fact, I could write a language with destructive updates for locals,
> and the generated code would be fast and efficient--and perfectly
> normal--Erlang.  The difference being that all the listing of
> parameters goes away, and the function is less dense and simpler to
> maintain.
> How do other Erlang programmers deal with this?
> James

Rich Beerman
Cupertino, California
mobile: 408/221-2444
fax: 408/255-7944

More information about the erlang-questions mailing list