Loren on the Art of MATLAB

Turn ideas into MATLAB

Note

Loren on the Art of MATLAB has been archived and will not be updated.

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;




Published with MATLAB® 7.7


  • print