How do I invoke a shadowed core MATLAB function (not built-in) from an overloaded function of same name

22 views (last 30 days)
In an application I wanted to add a calling jacket for MATLAB's print. I was trying to add a print option -dsvg which used the great resource plot2svg.m to print to .svg, while using MATLAB's regular print for all other cases.
If I name my function print() in my local project folder, I can shadow the main print function for this application only, but I cannot then call base MATLAB print inside my custom version of print. I had thought
builtin('print' ...)
would do the trick, but print is not built-in so cannot be accessed in this way. I could use run command which changes directory but that seems "dodgy" (one would want to use try-catch to preserve directory in the case of print failure, at least). I could give my function a different name, but then I have to locate and change every call to "print" in my app, which is exactly what I was seeking to avoid!
Is there an nice way of doing this? Any help gratefully received.

Accepted Answer

Julian
Julian on 14 Aug 2014
A colleague gave me this answer, which I have used. I put the following code into the top of my overlay function (print() in my case):
persistent shipped % stores a handle to the shipped MATLAB funtion of the same name
if isempty(shipped)
this = [mfilename '.m']; % the name of function in MATLAB we are shadowing
list = which(this, '-all'); % find all the functions which shadow it
f = strncmp(list, matlabroot, length(matlabroot)); % locate 1st in list under matlabroot
list = list{find(f, 1)}; % extract from list the exact function we want to be able to call
here = cd(list(1:end-length(this))); % temporarily switch to the containing folder
shipped = str2func(this(1:end-2)); % grab a handle to the function
cd(here); % go back to where we came from
end
The first time it is used it locates the base MATLAB function which is shadowed by the function containing the above code, and creates a handle to the base function which is available for all subsequent calls to use as needed.
  3 Comments
Adam Danz
Adam Danz on 28 Sep 2020
Edited: Adam Danz on 26 Mar 2021
+1 I've used and recommended this solution several times.
The version below make the following changes:
  • uses fileparts to isolate the path and file name rather than using string indexing
  • replaces length with numel which is more robust but makes no difference in this case.
  • Uses onCleanup to return the cd() in case of errors.
  • If a shadowed core function is not found, instead of resulting in an error, this will store the files' name as the shipped function handle.
Also be aware that the function and file name must match. This, therefore, cannot be used with local or nested functions.
persistent shipped % stores a handle to the shipped MATLAB funtion of the same name
if isempty(shipped)
this = [mfilename '.m']; % the name of function in MATLAB we are shadowing
list = which(this, '-all'); % find all the functions which shadow it
f = strncmp(list, matlabroot, numel(matlabroot)); % locate 1st in list under matlabroot
if any(f)
[funcpath,funcname] = fileparts(list{find(f, 1,'first')}); % extract from list the exact function we want to be able to call
here = cd(funcpath); % temporarily switch to the containing folder
cleanup = onCleanup(@()cd(here)); % go back to where we came from
shipped = str2func(funcname); % grab a handle to the function
clear('cleanup')
else
shipped = str2func(['@',mfilename]);
end
end
user001
user001 on 26 Mar 2021
This does not work if the shadowing function is in a private directory, since private functions have higher precedence than the current directory. Is there any solution in that case?

Sign in to comment.

More Answers (1)

Christopher Berry
Christopher Berry on 14 Aug 2014
Edited: Christopher Berry on 14 Aug 2014
Julian,
I think you had the right idea with the run command to call print, but use the fullpath instead of cd into the directory. You can also use matlabroot to keep your script portable as well:
printMatlab = fullfile(matlabroot,'toolbox','matlab','graphics','print.m');
run(printMatlab)
As long as the script (here just print) does not change the directory it is in, run will return to the correct working directory on success or failure, so you do not need to worry about using try-catch yourself.
  3 Comments
Christopher Berry
Christopher Berry on 14 Aug 2014
You are right, without arguments print is not all that useful. I was looking for a way around this when I saw your post.
Julian
Julian on 14 Aug 2014
A subsidiary question emerges though, how might I reference the help in the base / shipped function? If I put "See also PRINT" in my print overlay, clicking it just echoes the help in my function, rather than produce the help for the shadowed function....

Sign in to comment.

Categories

Find more on Structures in Help Center and File Exchange

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!