by Richard Russell, May 2006
Programs frequently need to contain a cleanup routine which gets called before the program quits. Such a routine may close files, remove open dialogue boxes, free Windows resources that have been allocated (e.g. memory or graphics objects) etc. So the routine will typically include code similar to the following:
DEF PROCcleanup CLOSE #Outfile% PROC_closedialog(Dialogue%) SYS "GlobalFree", Memory% ENDPROC
The cleanup code will need to be executed not only on the normal exit from the program but also if a premature exit takes place because of an error (including Escape) or the user clicking on the Close button. Therefore it is likely that the routine will be called from both ON ERROR and ON CLOSE statements:
ON CLOSE PROCcleanup : QUIT ON ERROR SYS "MessageBox", @hwnd%, REPORT$, 0, 48 : PROCcleanup : QUIT
But this immediately causes a problem. What happens if the premature exit occurs before one or more of the variables used in PROCcleanup have been created? The result would be a No such variable error, which would activate the ON ERROR routine, which would call PROCcleanup, which would result in another error and so on ad infinitum. This is not good!
What is needed is a way of forcing a variable to exist if it doesn't already, but leaving its value unchanged if it does. Fortunately BBC BASIC provides two ways of doing this:
variable = variable variable += 0
Both these have the same effect: if variable already exists it is left unaltered, if variable doesn't exist it is created and its value is set to zero. Obviously there are a number of other equivalent operations such as “variable *= 1” but the two listed are the ones most commonly used.
So armed with this knowledge we can now modify PROCcleanup so that it never fails with a No such variable error:
DEF PROCcleanup Outfile% += 0 : IF Outfile%<>0 CLOSE #Outfile% Dialogue% += 0 : IF Dialogue%<>0 PROC_closedialog(Dialogue%) Memory% += 0 : IF Memory%<>0 SYS "GlobalFree", Memory% ENDPROC
Of course this relies on the normal values of the variables never being zero, but in general that is the case.
You can use this technique whenever you can't be sure whether a variable has been created or not.
Added by JGH, May 2006
This can be improved a little. What would happen if PROCcleanup was called again? If Outfile% was still nonzero, it would attempt to close a channel that has already been closed. After the cleanup operation the variable should be set to zero, eg CLOSE#Outfile%:Outfile%=0.
If PROCcleanup is called by ON ERROR, what happens if the cleanup causes an error? It is called again. If, for example, CLOSE#Outfile% causes an error, PROCcleanup will be called again, which will then try to do CLOSE#Outfile% again, which will cause an error…
What I prefer to do is zero the variable before doing the cleanup, which means if the cleanup is called again an invalid cleanup isn't attempted.
DEF PROCcleanup LOCAL temp% Outfile% += 0 :IF Outfile% :temp%=Outfile% :Outfile%=0 :CLOSE #temp% Dialogue% += 0 :IF Dialogue%:temp%=Dialogue%:Dialogue%=0:PROC_closedialog(temp%) Memory% += 0 :IF Memory% :temp%=Memory% :Memory%=0 :SYS "GlobalFree", temp% ENDPROC
This is the technique I use in my BASIC program libraries, such as the Close library.