When MATLAB Refreshes Directories
Over the years, there have been lots of questions about when MATLAB recognizes files on the path. Today I'm going to talk about the case where a user generates or updates MATLAB code, and then wants to use it. What do you have to do to be sure MATLAB sees it? I am specifically talking about user files in user directories and NOT about files underneath matlabroot.
Contents
function fcnPuzzle()
Note: I am doing an experiment by publishing a function with subfunctions so you can see the code with the benefit of syntax highlighting for the code that's not the blog-code itself. I hope this ends up working and being helpful.
The Code That Perplexed
See the function fcnBug towards the bottom of this post. One puzzle is that if you run the code from the debugger, the results are always the expected ones, but not when running the usual way. I'll illustrate the conundrum by running it a few different ways. Also see the repaired version fcnBugRepair following the buggy version.
Show the file doesn't exist.
exist('fcnTest.m','file')
ans = 0
Small puzzle. If I don't put my first attempt, before the file exists, into a try-catch, my function fails with an error. However, if I place the same code inside a try-catch, it seems to not generate the error. Let's ignore that mystery for today.
try fcnBug( 'C', 'clear') catch ignoreException disp('error when file doesn''t exist before running') end
Only the original function written out is called, not the updated versions, assuming we do nothing else in the function to affect the workspace.
for d=1:4 fcnBug( num2str(d), 'nothing') end
1 Problem 1 Problem 1 Problem 1 Problem
Clearing the function before calling it helps.
for d=1:4 fcnBug( num2str(d), 'clear') end
1 Problem 2 Problem 3 Problem 4 Problem
Another way to influence MATLAB to see the new function is to ask if the file exists.
delete fcnTest.m for d=1:4 fcnBug(num2str(d), 'clear+exist') end
1 Problem 2 Problem 3 Problem 4 Problem
Clean up.
delete fcnTest.m
Fixing the Problem
There is an easy solution to being sure that the new file is recognized. Directly after closing the file, force MATLAB to clear the one in memory. You can do this with a lighter or heavier hand, depending on your situation. Simply clearing the function is enough, or you might try to rehash the files MATLAB knows about.
try fcnBugRepair( 'C', 'clear') catch ignoreException disp('error when file doesn''t exist before running') end
error when file doesn't exist before running
Let me show this working with the repaired function. This was the case earlier in which only the file originally written out was called. You can see here that each version is now executed, even when nothing additional is done (except the addition of the clear statement in the function code).
for d=1:4 fcnBugRepair( num2str(d), 'nothing') end
1 Problem 2 Problem 3 Problem 4 Problem
As before, clearing the workspace before execution still has the good effect.
for d=1:4 fcnBugRepair( num2str(d), 'clear') end
1 Problem 2 Problem 3 Problem 4 Problem
Again, the test for function existence also works.
delete( 'fcnTest.m'); for d=1:4 fcnBugRepair(num2str(d), 'clear+exist') end
1 Problem 2 Problem 3 Problem 4 Problem
Clean Up
delete fcnTest.m
Why Does This Solution Work?
The problem is that of timestamp resolution for the file, which on most filesystems is only 1 second. Since this is being run in a tight loop, the file fcnTest.m is being rewritten during the same clock tick and therefore MATLAB has no way of knowing that it has changed. Therefore, MATLAB originally continued to use the cached version.
clear forces MATLAB to dump its cache, and the next time MATLAB runs the function it reloads it from disk.
The functions exist and rehash each cause MATLAB to notice the file change because they each refresh "dirty" directories.
The reason MATLAB doesn't always look for changes is for performance. fclose does notify the path manager that a certain directory is changed but the cache update won't happen until someone explicitly refreshes the directory -- the refreshing can happen in the ways I've already discussed, or at the next command prompt (that is why it works in debugger).
Original Function
function fcnBug( id, mode)
% fcnBug - unexpected bug % % %% Error % % when the file does not exist before run % fcnBug( 'C', 'clear') % %% Only the 'base workspace one' % % is called % for d=1:4 % fcnBug( num2str(d), 'nothing') % end % %% Clear the workspace % % helps % for d=1:4 % fcnBug( num2str(d), 'clear') % end % %% Not at creation time % delete( 'fcnTest.m'); % fcnBug( num2str(1), 'clear') % %% Exists % % seems to tell to MATLAB that a function is here % delete( 'fcnTest.m'); % for d=1:4 % fcnBug(num2str(d), 'clear+exist') % end fid = fopen('.\fcnTest.m', 'w'); fprintf(fid, 'function fcnTest(varargin)\ndisp(''%s Problem'')', id); fclose(fid); switch lower(mode) case 'clear+exist' clear fcnTest exist( 'fcnTest.m', 'file'); case 'clear' clear fcnTest case 'nothing' end fcnTest;
error when file doesn't exist before running
Repaired Function
function fcnBugRepair( id, mode) % Repaired by adding clear statement in a good location fid = fopen('.\fcnTest.m', 'w'); fprintf(fid, 'function fcnTest(varargin)\ndisp(''%s Problem'')', id); fclose(fid); clear fcnTest % or could use rehash here instead switch lower(mode) case 'clear+exist' clear fcnTest exist( 'fcnTest.m', 'file'); case 'clear' clear fcnTest case 'nothing' end fcnTest;