Main Content

Clean Up When Functions Complete

Overview

A good programming practice is to make sure that you leave your program environment in a clean state that does not interfere with any other program code. For example, you might want to

  • Close any files that you opened for import or export.

  • Restore the MATLAB® path.

  • Lock or unlock memory to prevent or allow erasing MATLAB function or MEX-files.

  • Set your working folder back to its default if you have changed it.

  • Make sure global and persistent variables are in the correct state.

MATLAB provides the onCleanup function for this purpose. This function, when used within any program, establishes a cleanup routine for that function. When the function terminates, whether normally or in the event of an error or Ctrl+C, MATLAB automatically executes the cleanup routine.

The following statement establishes a cleanup routine cleanupFun for the currently running program:

cleanupObj = onCleanup(@cleanupFun);

When your program exits, MATLAB finds any instances of the onCleanup class and executes the associated function handles. The process of generating and activating function cleanup involves the following steps:

  1. Write one or more cleanup routines for the program under development. Assume for now that it takes only one such routine.

  2. Create a function handle for the cleanup routine.

  3. At some point, generally early in your program code, insert a call to the onCleanup function, passing the function handle.

  4. When the program is run, the call to onCleanup constructs a cleanup object that contains a handle to the cleanup routine created in step 1.

  5. When the program ends, MATLAB implicitly clears all objects that are local variables. This invokes the destructor method for each local object in your program, including the cleanup object constructed in step 4.

  6. The destructor method for this object invokes this routine if it exists. This perform the tasks needed to restore your programming environment.

You can declare any number of cleanup routines for a program file. Each call to onCleanup establishes a separate cleanup routine for each cleanup object returned.

If, for some reason, the object returned by onCleanup persists beyond the life of your program, then the cleanup routine associated with that object is not run when your function terminates. Instead, it will run whenever the object is destroyed (e.g., by clearing the object variable).

Your cleanup routine should never rely on variables that are defined outside of that routine. For example, the nested function shown here on the left executes with no error, whereas the very similar one on the right fails with the error, Undefined function or variable 'k'. This results from the cleanup routine's reliance on variable k which is defined outside of the nested cleanup routine:

function testCleanup               function testCleanup
k = 3;                             k = 3;
myFun                              obj = onCleanup(@myFun);
    function myFun                     function myFun
    fprintf('k is %d\n', k)            fprintf('k is %d\n', k)
    end                                end
end                                end

Examples of Cleaning Up a Program Upon Exit

Example 1 — Close Open Files on Exit

MATLAB closes the file with identifier fid when function openFileSafely terminates:

function openFileSafely(fileName)
fid = fopen(fileName, 'r');
c = onCleanup(@()fclose(fid));

s = fread(fid);
     .
     .
     .
end

Example 2 — Maintain the Selected Folder

This example preserves the current folder whether functionThatMayError returns an error or not:

function changeFolderSafely(fileName)
   currentFolder = pwd;
   c = onCleanup(@()cd(currentFolder));

   functionThatMayError;
   end   % c executes cd(currentFolder) here.

Example 3 — Close Figure and Restore MATLAB Path

This example extends the MATLAB path to include files in the toolbox\images folders, and then displays a figure from one of these folders. After the figure displays, the cleanup routine restore_env closes the figure and restores the path to its original state.

function showImageOutsidePath(imageFile)
fig1 = figure;
imgpath = genpath([matlabroot '\toolbox\images']);

% Define the cleanup routine.
cleanupObj = onCleanup(@()restore_env(fig1, imgpath));

% Modify the path to gain access to the image file, 
% and display the image.
addpath(imgpath);
rgb = imread(imageFile);
fprintf('\n   Opening the figure %s\n', imageFile);
image(rgb);
pause(2);

   % This is the cleanup routine.
   function restore_env(fighandle, newpath)
   disp '   Closing the figure'
   close(fighandle);
   pause(2)
   
   disp '   Restoring the path'
   rmpath(newpath);
   end
end

Run the function as shown here. You can verify that the path has been restored by comparing the length of the path before and after running the function:

origLen = length(path);

showImageOutsidePath('greens.jpg')
   Opening the figure greens.jpg
   Closing the figure
   Restoring the path

currLen = length(path);
currLen == origLen
ans =
     1

Retrieving Information About the Cleanup Routine

In Example 3 shown above, the cleanup routine and data needed to call it are contained in a handle to an anonymous function:

@()restore_env(fig1, imgpath)

The details of that handle are then contained within the object returned by the onCleanup function:

cleanupObj = onCleanup(@()restore_env(fig1, imgpath));

You can access these details using the task property of the cleanup object as shown here. (Modify the showImageOutsidePath function by adding the following code just before the comment line that says, “% This is the cleanup routine.”)

disp '   Displaying information from the function handle:'
task = cleanupObj.task;
fun = functions(task)
wsp = fun.workspace{2,1}
fprintf('\n');
pause(2);

Run the modified function to see the output of the functions command and the contents of one of the workspace cells:

showImageOutsidePath('greens.jpg')

Opening the figure greens.jpg
Displaying information from the function handle:
fun = 
     function: '@()restore_env(fig1,imgpath)'
         type: 'anonymous'
         file: 'c:\work\g6.m'
    workspace: {2x1 cell}
wsp = 
     imageFile: 'greens.jpg'
          fig1: 1
       imgpath: [1x3957 char]
    cleanupObj: [1x1 onCleanup]
           rgb: [300x500x3 uint8]
          task: @()restore_env(fig1,imgpath)

Closing the figure
Restoring the path

Using onCleanup Versus try/catch

Another way to run a cleanup routine when a function terminates unexpectedly is to use a try, catch statement. There are limitations to using this technique however. If the user ends the program by typing Ctrl+C, MATLAB immediately exits the try block, and the cleanup routine never executes. The cleanup routine also does not run when you exit the function normally.

The following program cleans up if an error occurs, but not in response to Ctrl+C:

function cleanupByCatch
try
    pause(10);
catch
    disp('   Collecting information about the error')
    disp('   Executing cleanup tasks')
end

Unlike the try/catch statement, the onCleanup function responds not only to a normal exit from your program and any error that might be thrown, but also to Ctrl+C. This next example replaces the try/catch with onCleanup:

function cleanupByFunc
obj = onCleanup(@()...
    disp('   Executing cleanup tasks'));
pause(10);

onCleanup in Scripts

onCleanup does not work in scripts as it does in functions. In functions, the cleanup object is stored in the function workspace. When the function exits, this workspace is cleared thus executing the associated cleanup routine. In scripts, the cleanup object is stored in the base workspace (that is, the workspace used in interactive work done at the command prompt). Because exiting a script has no effect on the base workspace, the cleanup object is not cleared and the routine associated with that object does not execute. To use this type of cleanup mechanism in a script, you would have to explicitly clear the object from the command line or another script when the first script terminates.