There are several cases, in which a program has to do operations A,B,C. If an error occurs while doing A, the program needs to undo A. If there is an error while doing B, the program needs to undo B then A. Similarly, an error in C requires undoing of C,B,A in this sequence.
Written in pseudo C (the example was taken from http://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/), it looks like the following (replacing ‘do’ by ‘perform’ and ‘undo’ by ‘reverse’):
perform A
if (error)
goto out_a;
perform B
if (error)
goto out_b;
perform C
if (error)
goto out_c;
goto out;
out_c:
reverse C
out_b:
reverse B:
out_a:
reverse A
out:
return ret;
I would like to propose a language construct which would express the above: do/undo. It would work similarly to try/catch in languages which support exception handling. The above example, rewritten using do/undo, would be as follows.
do {
perform A
if (error)
undo;
do {
perform B
if (error)
undo optional_label_B;
do {
perform C
if (error)
undo;
}
undoing {
reverse C
}
}
optional_label_b: undoing {
reverse B
}
}
undoing {
reverse A
}
return ret;
Advantages:
- Structured code, allowing the compiler to catch structural errors.
Disadvantages:
- Requires indentation.
- Needs three reserved keywords (do, undo, undoing).