Skip to content

Instantly share code, notes, and snippets.

@andytill
Last active February 20, 2023 06:00
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save andytill/878ef84a8bc886887f3b to your computer and use it in GitHub Desktop.
Save andytill/878ef84a8bc886887f3b to your computer and use it in GitHub Desktop.
Erlang Project Ideas

When I started erlang, I had a hard time thinking of ideas for projects to improve my skills. Now I have way too many ideas to possibly implement Myself. Since I actually want these projects to exist so I can use them (everlasting glory coming secondary to some handy tools) I have written them up here. Feel free to try them out. I'm open to questions and suggestions.

swagger for erlang

swagger is a JSON spec for REST APIs. Once you have written a spec in swagger, it can generate documentation (demo) and REST handlers.

An erlang swagger library should take swagger specs and generate cowboy_rest handlers for them.

Difficulty: low

pretty print stack traces in lager

lager writes logs to files and pretty_errors pretty prints stack traces, a perfect match!

Modify the lager formatter to pretty print errors as shown in the pretty_errors project page.

Difficulty: low

edoc manpage generator (fempage?)

Looking up erlang manpage doc using editor plugins such as sublime-erlyman is much more responsive than web documentation. It would be great to be able to lookup docs for my own code and deps using manpages. The edown project is a good place to start for edoc integration.

Difficulty: low/medium

OTP standard library expansion

The erlang library is quite minimal. When coding list and binary operations I always have to roll my own implementations for the same functions:

  • lists:unique/1 remove duplicate elements in a list, preserving order.
  • lists:interpolate/2 Insert a term inbetween each element in the list. The type of the list elements or the the term inserted between is not checked, the result is a proper (flat) list unless the element inserted was also a list e.g. [a,x,b,x,c] = lists:interpolate(x, [a,b,c]).
  • binary:to_lower Convert upper case ascii in a binary to lower case.
  • binary:to_upper Convert lower case ascii in a binary to upper case.
  • binary:trim Standard left/right/both trim functions for binary strings.
  • binary:ends_with Check if a given binary ends with another binary true = binary:ends_with(<<"hello">>, <<"llo">>) It is simple to find if a binary starts with certain data using the binary matching syntax, it is a few more lines if you need to know if a binary ends with another binary.

Difficulty: medium

Difficulty is considered per function. It is relatively straightforward to get to grips with the OTP code for lists, the binary module involves much more c code so could be easier or more difficult depending on your experience.

Remember to add tests and documentation.

UI for dbg module (erlyberly)

One of the biggest misnomers about erlang is that the debugger doesn't work and programmers never use it anyway. I haven't had a great experience with the erlang graphical debugger but the dbg module is far better once you get used to it and can be used on running systems in test or production environments.

It would be handy to have a UI that connects as a remote note, presents a tree of modules and functions and allows you to set dbg traces on them and present you with those traces. It should be possible to do a text search on those traces as well.

I have made a start on this project at https://github.com/andytill/erlyberly.

Difficulty: medium

Parse Transform for alternate guard syntax

I don't like the syntax for guards. For me, it is far more inelegant than other erlang language constructs. For example:

my_func(Value) when is_binary(Value) ->
    ok.

This is just one guard, if you check more than one argument they can quickly stack up. Now compare this to binary syntax:

<<Length:32, _/binary>> = Value.

I find this is as elegant as it could possibly be. The /type is particularly nice, why not apply it function arguments?

my_func(Value/binary) ->
    ok.
    
% not just for binaries!
    
my_func2(Value/atom) ->
    ok.

This is very understandable to me, and looks like other erlang syntax I am used to dealing with. The two pieces of code would be equivalent, the proposed syntax just a shorthand for the guard. The syntax doesn't have to handle the more complicated guards just the type checks which are most common anyway.

I have made a start on this, it isn't as difficult as I imagined. See the ohmyguard project here.

Better record field access

Record syntax is very very bad. They are verbose and duplicated code is everywhere. Having to unpack the variables or need to express the record type is not required in any other language I have seen. For example:

State#state.my_field
#state{ my_field = MyField } = State

How I think it should work is if I can prove to the compiler than a variable is one record type then the fields should be directly accessible. For example:

my_func(State) when is_record(State, state) ->
    State.my_field.

The compiler would know that in this example the function body could not be executed if State was not the state record, so it is safe to infer the type of record.

How would it look if it was combined with the alternate guard syntax proposed above?

my_func(State/#state) ->
    State.my_field.

erlang records are starting to look good! These two features are completely separate, but complementary.

Update: this already exists as a parse transform, check out the recless project. This is hosted on Google code so expect it to move in the next few months.

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