Where is it appropriate to do input validation in Erlang

erlang

I'm writing a module that runs a finite state machine* based on the contents of an array of records passed in at initialization. Each record describes a state and includes instructions on how to act on inputs (i.e., when in state S1, input I triggers a transition to state S2). For the FSM to work correctly, the transitioned-to states need to exist.

My quandary is where to validate those transitions.

The defensive programmer in me says to do it once as early as possible, such as when the FSM is initialized. This means I can raise an error when I'm first handed bogus data and avoid handing back a process that may fail later as a result. The rest of the implementation won't have to be as defensive because the table is known to be good and any errors that Erlang decides to raise will be a result of implementation rather than having being fed bad data. It will also make debugging easier for those using the module since they'll get a badarg or something else back immediately instead of having to paw through my sources later to figure out that it was their mistake and not mine.

The Erlang philosophy seems to be that things should be left to run as long as possible, failing only when they have to and letting a supervisor take care of picking up the pieces. On one hand, this makes sense because a given FSM could run forever without encountering the inputs it would take for a bad transition. On the other, failing late puts the onus on the callers to write repetitive tests for something that's easy for me implement once.

I know that most rules in this business aren't hard and fast, but is one approach more "Erlangy" than the other? Would a fail-early implementation appear out of place if released for others to use?


*I am aware of the gen_fsm behaviour and that what I'm doing has some comparative shortcomings. This is a learning exercise for some other things, and a FSM happens to be something that incorporates them.

Best Answer

The reason it seems less "Erlangy" to do onerous type checking is because the language is dynamically typed.

If you really need to ensure that data of a certain type is used, you can use the is_TYPE/1 functions to verify your input as guard expressions. You should do this as early as you are able.

http://learnyousomeerlang.com/types-or-lack-thereof