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

24 visualizaciones (últimos 30 días)
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.

Respuesta aceptada

Julian
Julian el 14 de Ag. de 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 comentarios
Adam Danz
Adam Danz el 28 de Sept. de 2020
Editada: Adam Danz el 26 de Mzo. de 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 el 26 de Mzo. de 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?

Iniciar sesión para comentar.

Más respuestas (1)

Christopher Berry
Christopher Berry el 14 de Ag. de 2014
Editada: Christopher Berry el 14 de Ag. de 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 comentarios
Christopher Berry
Christopher Berry el 14 de Ag. de 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 el 14 de Ag. de 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....

Iniciar sesión para comentar.

Categorías

Más información sobre Structures en Help Center y File Exchange.

Productos

Community Treasure Hunt

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

Start Hunting!

Translated by