Tuesday, November 18, 2014

unimplemented callback

Erlang behaviour

Erlang provides mechanism of behaviours, which allows to guarantee API of certain module. If one of behaviour's callback is not implemented, compiler generates warning.

gen_server

Let's examine the importance of these warnings on example of gen_server. Of course, process can not be started and stopped correctly without implementing init/2 and terminate/2 callbacks. Then gen_server implements some payload: handle_info, handle_call or handle_cast.

Neglect of unexpected messages

If one of these callbacks is not needed, some people do some default implementation, for example, logging of unexpected message and proceeding of program execution. This approach allows to avoid compilation warnings, but may hide serious problem in system if careful log monitoring is not organised. Also function clause with the same logic, which matches on everything, is often appended to each callback.

Crash on unexpected message

Another option could be termination of the process via returning stop-tuple, which is sometimes much better. The only argument against is that it happens by default in OTP but via crashing.

Hot code upgrade

The last callback not covered is code_change. It does not require a dummy implementation. During hot code upgrade system uses the newest callback to update process's state.

gen_fsm

If problem of unused code in gen_server's callbacks does not look that serious comparing to possible advantages of handling all possible messages, let's analyse another standard OTP behaviour - gen_fsm. Besides handle_info, init, terminate and code_change, which have logic similar to gen_server, gen_fsm has a number of callbacks for handling different types of events.

All state events

All state events could be synchronous and asynchronous and are handled in handle_sync_event/4 and handle_event/3 correspondently. For handling of unexpected messages of that type both strategies from gen_server (ignoring and termination) are applicable with the same advantages and disadvantages.

Named events

"Named" events could be synchronous and asynchronous as well and are handled by StateName/3 and StateName/2 callbacks of gen_fsm behaviour, where StateName is the name of current state of FSM. Since names of these callbacks are dynamic, not implementing them does not lead to compilation warnings, but somebody could understand fault-tolerance as not-crashing in any circumstances including receiving of unexpected events.
One, who decides to achieve this, must be really tolerant, since he needs to accumulate state names from entire FSM, and implement StateName/3 and StateName/2 dummy function clauses for each of them. Also he needs to maintain such FSM with growing number of states.

Conclusion

It is recommended not to implement any behaviour's callback just for the sake of suppressing of compilation warnings or being pseudo-fault-tolerant to unexpected messages/situations. Each callback implementation needs to have business logic. It's better to spend time on system's test automation instead of trying to make system, which can survive (not crash) if something unexpected happens.