Skip to content

Instantly share code, notes, and snippets.

@xandkar
Last active August 29, 2015 14:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xandkar/cd39cd48ba94035235f0 to your computer and use it in GitHub Desktop.
Save xandkar/cd39cd48ba94035235f0 to your computer and use it in GitHub Desktop.
Labeled (and optional) arguments in Erlang

One of the things I found myself wishing I had in Erlang was labeled arguments. Even with common operations from stdlib (like lists:foldl) - I constantly forget the correct order of arguments, and it becomes that much more error-prone in complex cases (see cowboy_req:new/14, for instance).

Another desirable feature is optional arguments, which are assigned a default value when omitted.

It turns-out that the semantics of these requirements are fully met by records!

I only realized that when lamenting the lack of the same features in SML (as compared to OCaml, which does have them) and being pointed to an alternative - anonymous records.

However, proliferation of public record definitions is a bit problematic in Erlang, due to lack of features for managing name spaces, but even that can be resolved by following the same technique that is already used to solve this problem in modules: fully qualify any public name, i.e. foo_bar_baz, not just baz. To tidy things up even more, I think it is nice to keep public record definitions in dedicated .hrl files, i.e. foo_bar.hrl, foo_baz.hrl, not just records.hrl.

-module(module).
-include("module_args.hrl").
-export_type(
[ args_foo/0
]).
-export(
[ foo/1
]).
-type args_foo() ::
#module_args_foo{}.
-spec foo(args_foo()) ->
ok.
foo(#module_args_foo
{ bar = Bar
, baz = Baz
, qux = Quxicles
}
) ->
ok = do_stuff_with_quxicles(Quxicles, Bar, Baz).
-record(module_args_foo,
{ bar = <<"default">> :: binary()
, baz :: integer()
, qux = [] :: [stuff()]
}).
@AeroNotix
Copy link

So a record with default fields?

@andytill
Copy link

Also...

foo(bar, Bar, baz, Baz, qux, Quxicles) -> ok;

...although it doesn't do default args, or R17 maps.

@xandkar
Copy link
Author

xandkar commented Mar 19, 2015

@AeroNotix yep :)

@andytill The problem with that approach is that it not only doesn't solve the significant-ordering issue, but it exacerbates it, since now cowboy_req:new/14 becomes cowboy_req:new/28 - good luck remembering the order of labels :)

@andytill
Copy link

Very true, though I like fixed order parameters in functions. A 14 arity function, WTF!

@xandkar
Copy link
Author

xandkar commented Mar 23, 2015

Yeah, it's pretty-terrible. Somewhat common too, unfortunately. There're valid reasons for it, but I think we can do much better with specialized records.

https://github.com/ninenines/cowboy/blob/d2205d9ea6aa71ff256c48667755676d0e6c2377/src/cowboy_req.erl#L154

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment