[erlang-questions] Variable naming conventions
Richard O'Keefe
ok@REDACTED
Wed Apr 7 08:36:23 CEST 2010
On Apr 5, 2010, at 3:26 AM, Garrett Smith wrote:
(a) Multiple "versions" of a value named in the same scope.
I can tell you something worse that numeric suffixes, and that's
*no* annotation, so that you have to trace through the control
flow to find out which version you are looking at.
> handle_call(_, #state{name=Name}=State) ->
> UpdatedName = strip_white_space(Name),
> {noreply, State#state{name=UpdatedName)}}.
This can be written as
handle_call(_, State) ->
{noreply, State#state{name =
strip_white_space(State#State.name)}.
You could even refactor it as
state_sans_white_space_in_name(State = #state{name = Name})) ->
State#state{name = strip_white_space(Name)}.
handle_call(_, State) ->
{noreply, state_sans_white_space_in_name(State)}.
The real problem of repetition here is
State, state, State, State
name, Name, name,
So here is a general pattern: we have a variable V which is an instance
of record R and we want to update field F from old value O to new
value N.
-define(update(V,R,F,O,N), (#R{F=O}=V, V#R{F=N})).
handle_call(_, State) ->
{noreply, update(State, state,name, O, strip_white_space(O))}.
Or a higher order function:
update@REDACTED(F, State = #state{name = Old})
when is_function(F, 1) ->
State#state{name = F(Old)}.
handle_call(_, State) ->
{noreply, update@REDACTED(fun strip_white_space/1, State)}.
> The other frustrating case -- and far more so -- is something like
> this:
>
> Name = case get_name() of
> undefined -> "";
> {ok, NameValueReturnedByGetName} -> NameValueReturnedByGetName
> end
>
> (I'm calling this "leakage" because I'd probably just call it Name if
> it didn't leak. While that'd be clunky, it at least says what I think
> it should.)
But you can perfectly well write
case get_name() of undefined -> Name = "" ; {ok, Name} -> ok end
There is some feeling in the Erlang community against exporting variable
bindings from 'case'. I reckon sometimes it's a good idea, sometimes
not.
In cases like this where you are supplying a "default" for a function
that didn't have one, again, write a function.
get_name(Default_Name) ->
case get_name()
of undefined -> Default_Name
; {ok, Name} -> Name
end.
and then use
Name = get_name("")
Presto chango, no leakage. If you like longer names,
get_name_with_default/1 might be clearer.
Or if you have several functions with a common
undefined | {ok, X} result type, you could use
with_default(undefined, Default) -> Default;
with_default({ok, Value}, _) -> Value.
Name = with_default(get_name(), "")
> I know I can refactor this into a function and solve the problem, but
> of course there are cases where I don't want to.
So of course the best thing to do is to show us one of those cases.
There's an "old" Erlang style that goes back before Erlang had
funs at all. (And there were good reasons to stay with a first-order
language.) With the introduction of funs, it is possible to move
closer to an ML or Haskell style.
More information about the erlang-questions
mailing list