Overloading the ! (bang) operator - matlab

In the answer to this question the MathWorks Support Team states that:
It is also possible to overload the ! (bang) operator by creating a
file called "!.m" and having this file be before the directory
$MATLABROOT\toolbox\matlab\general in the MATLAB search path.
I have tried this and it doesn't seem to work. I am running Matlab 9.1.0.441655 (R2016b) on Linux Mint. My path looks like that:
/home/raphael/Programs/Test
/usr/local/MATLAB/R2016b/toolbox/matlab/iofun
...
/usr/local/MATLAB/R2016b/toolbox/matlab/general
...
and I have created a file !.m in /home/raphael/Programs/Test. Whatever I put in this file the editor displays an error:
Line 1: Unable to run code analysis. '/home/raphael/Programs/Test/!.m' is an invalid file name.
As the ! (bang) operator is not listed in the Operators and associated function list, it is unclear what to put inside the !.m file.
I have nevertheless tried to put some code:
function bang(c)
disp(c)
but though which ! returns my custom file path, Matlab invariably calls the built-in operator:
>> which !
/home/raphael/Programs/Test/!.m
>> !pwd
/home/raphael/Programs/Test
Renaming the file to bang.m resolves the error but has no effect on the bang operator.
So:
Did Matlab's behavior changed since R2012?
How could one overload the ! (bang) operator?
And if this is actually possible, what should be the syntax of the function declaration?

It looks like this undocumented handling of !.m disappeared in R2015b (presumably with the new execution engine changes that were also introduced with that release).
For versions earlier than R2015b, you can indeed name a file !.m on the path and then the name of the function within the file doesn't matter (as it never does in MATLAB).
!.m
function bang(varargin)
disp('bang!')
end
In current versions of MATLAB, the ! operator will ignore your !.m file but will call the underlying system, unix, or dos commands. Therefore you'll need to overload those commands instead.
So on OS X, overloading just unix.m does the trick:
unix.m
function varargout = unix(varargin)
disp('My Unix Command')
[varargout{1:nargout}] = builtin('unix', varargin{:});
end

Related

How to locate where a built-in function is defined?

In MATLAB, there are roughly 3 ways to define functions: non-comment-only .m files, .p files, and compiled code (e.g. DLL, MEX).
Knowing where a function is defined could be helpful in several cases, such as when a breaking change was introduced to some function outside our control, and we'd like to try to revert to an old version in the hopes of getting our code working again; or when trying to reverse-engineering some undisclosed algorithm.
The which function is usually very good at identifying function definitions and their locations (which works for .m, .p and MEX), but isn't very useful when it comes to shared library functions, where (at best) it points to a comment-only documentation file:
>> which _mcheck
built-in (undocumented)
>> which svd
built-in (D:\Program Files\MATLAB\R2019a\toolbox\matlab\matfun\svd)
If so, assuming a function found within a shared library is called during the execution of my code, how can I locate the specific file (DLL) that contains it?
It turns out that dbstop can be used for this. For example:
>> which svd
built-in (D:\Program Files\MATLAB\R2019a\toolbox\matlab\matfun\svd)
>> dbstop svd
Warning: Entering debug mode is only supported within running MATLAB code files.
Warning: MATLAB debugger can only stop in MATLAB code files, and "libmwmathlinalg>svd" is not a MATLAB code file.
Instead, the debugger will stop at the point right before "libmwmathlinalg>svd" is called.
From there's it's just a matter of finding a file called libmwmathlinalg (with the relevant extension) - which isn't a difficult task if your drive is indexed.

Matlab Calling Functions without parentheses

What is the correct name for the situation where a Matlab-script calls a function, but provides arguments without parentheses?
Example:
clear xx
Alternatively, I could use parentheses and transfer a string with the variable name:
clear('xx')
How can I distinguish between both alternatives when googling for a solution?
Bonus Question: How can I put the content of a variable into a call that is NOT using parentheses? Specifically, a build-script using mcc with a dynamic -o filename option; calling mcc with parentheses would also be acceptable, but I don't know how to google that, hence this question.
Thank you!
When you call a function without the brackets, it is called command syntax. Here are three links to relevant documentation:
syntax
command vs function syntax
scripts and functions
Bonus answer
You cannot use a variable when using command syntax. From the docs:
When calling a function using command syntax, MATLAB passes the arguments as character vectors.
So it would work like so:
abc = zeros(10); % Some matrix called abc
mystring = 'abc' % A string containing the variable name
% Option 1:
clear('abc') % Clears the variable abc
% Option 2:
clear abc % As per above docs quote, interpreted as clear('abc')
% Option 3:
clear mystring % As per option 2, interpreted as clear('mystring') so doesn't work
% Option 4:
clear(mystring) % Interpreted as clear('abc') so works as expected
When calling mcc as you suggest in the question, the tooltip shows you can in fact use function syntax, despite the documentation being entirely shown using command syntax.
Notes
Using brackets is standard practise in MATLAB, since you also cannot get output values from a function when using command syntax.
Also from the 3rd docs link above, you can see a message discouraging the use of command syntax when using MATLAB.
Caution: While the unquoted command syntax is convenient, in some cases it can be used incorrectly without causing MATLAB to generate an error.

Why a command like combnk(1:3,2) does not work in Matlab 2011a?

Does anyone know why one can't use the command
combnk(1:3,2)
in Matlab 2011a, or is there any way to make this built-in function working? The error message I got is
???Undefined function or method 'combnk' for input arguments of type 'double'.
The two most common reasons for Undefined function or method-errors are (1) typos, and (2) lack of the appropriate toolbox.
If you're sure you didn't make any spelling mistake, try ver on the command line to check which toolboxes you have installed. If the statistics toolbox is missing, there won't be combnk on the path.
additional tip by Colin T Bowers
If ver indicates you do have the statistics toolbox, then try which combnk. If this returns combnk not found, then you may need to refresh your path, with something like restoredefaultpath then savepath

How does scoping in Matlab work?

I just discovered (to my surprise) that calling the following function
function foo()
if false
fprintf = 1;
else
% do nothing
end
fprintf('test')
gives and error Undefined function or variable "fprintf". My conclusion is that the scope of variables is determined before runtime (in my limited understanding how interpretation of computer languages and specifically Matlab works). Can anyone give me some background information on this?
Edit
Another interesting thing I forgot to mention above is that
function foo()
if false
fprintf = 1;
else
% do nothing
end
clear('fprintf')
fprintf('test')
produces Reference to a cleared variable fprintf.
MATLAB parses the function before it's ever run. It looks for variable names, for instance, regardless of the branching that activates (or doesn't activate) those variables. That is, scope is not determined at runtime.
ADDENDUM: I wouldn't recommend doing this, but I've seen a lot of people doing things with MATLAB that I wouldn't recommend. But... consider what would happen if someone were to define their own function called "false". The pre-runtime parser couldn't know what would happen if that function were called.
It seems that the first time the MATLAB JIT compiler parses the m-file, it identifies all variables declared in the function. It doesn't seem to care whether said variable is being declared in unreachable code. So your local fprintf variable immediately hides the builtin function fprintf. This means that, as far as this function is concerned, there is no builtin function named fprintf.
Of course, once that happens, every reference within the function to fprintf refers to the local variable, and since the variable never actually gets created, attempting to access it results in errors.
Clearing the variable simply clears the local variable, if it exists, it does not bring the builtin function back into scope.
To call a builtin function explicitly, you can use the builtin function.
builtin( 'fprintf', 'test' );
The line above will always print the text at the MATLAB command line, irrespective of local variables that may shadow the fprintf function.
Interesting situation. I doubt if there is detailed information available about how the MATLAB interpreter works in regard to this strange case, but there are a couple of things to note in the documentation...
The function precedence order used by MATLAB places variables first:
Before assuming that a name matches a function, MATLAB checks for a variable with that name in the current workspace.
Of course, in your example the variable fprintf doesn't actually exist in the workspace, since that branch of the conditional statement is never entered. However, the documentation on variable naming says this:
Avoid creating variables with the same name as a function (such as i, j, mode, char, size, and path). In general, variable names take precedence over function names. If you create a variable that uses the name of a function, you sometimes get unexpected results.
This must be one of those "unexpected results", especially when the variable isn't actually created. The conclusion is that there must be some mechanism in MATLAB that parses a file at runtime to determine what possible variables could exist within a given scope, the net result of which is functions can still get shadowed by variables that appear in the m-file even if they don't ultimately appear in the workspace.
EDIT: Even more baffling is that functions like exist and which aren't even aware of the fact that the function appears to be shadowed. Adding these lines before the call to fprintf:
exist('fprintf')
which('fprintf')
Gives this output before the error occurs:
ans =
5
built-in (C:\Program Files\MATLAB\R2012a\toolbox\matlab\iofun\fprintf)
Indicating that they still see the built-in fprintf.
These may provide insight:
https://www.mathworks.com/help/matlab/matlab_prog/base-and-function-workspaces.html
https://www.mathworks.com/help/matlab/matlab_prog/share-data-between-workspaces.html
This can give you some info about what is shadowed:
which -all
(Below was confirmed as a bug)
One gotcha is that Workspace structs, and classes on the path, have particular scoping and type precedence that (if you are me) may catch you out.
E.g. in 2017b:
% In C.m, saved in the current directory
classdef C
properties (Constant)
x = 100;
end
end
% In Command window
C.x = 1;
C.x % 100
C.x % 1 (Note the space)
C.x*C.x % 1
disp(C.x) % 1

Avoid MATLAB startup warning when overloading buildin functions?

As described here, I created my own figure.m which nicely overloads the built-in figure command. Now, whenever I start MATLAB I get the warning
Warning: Function C:\somepath\figure.m has
the same name as a MATLAB builtin. We
suggest you rename the function to
avoid a potential name conflict.
Is there any way to deactivate this warning, given that it is desired behavior in my case?
You might say that I should call my function differently instead of overloading, but I do feel for my development system this overloading is the right way to go...
Update
As mentioned by Aabaz you can globally turn off this warning using
warning off MATLAB:dispatcher:nameConflict
which needs to go at the beginning of matlabrc.m (before the path is set). However, I would still be interested in a solution which could specificially remove this error message for overloading figure.m (or some self-defined list of functions) instead of for all functions. I guess I'm asking a bit too much here ;-) ?
I cannot seem to replicate this warning with my Matlab version (R2008b) but anyway If you did not already try it you should look into the functions lastwarn and warning that allow you to identify and turn off this warning.
PS: the warning eventually came for some reason and I was able to use lastwarn and warning to turn it off.
>>[msgstr msgid]=lastwarn;
>>disp(msgid);
MATLAB:dispatcher:nameConflict
>>warning('off',msgid);
I should add that you should turn it off at startup for this to be effective between different sessions of Matlab.
I just ran into this problem on MATLAB R2014b where I also wanted to override figure. I think this is the closest solution to your updated question (3.5 years later...).
I think using the "dirty" trick from your comment is actually the cleanest, if done smartly as it doesn't require you to change matlabrc.m and can suppress the warning for only functions that you want to override built-in ones.
Put all your default overrides in a folder that is not on your permanent MATLAB path. I keep mine in ~/Documents/MATLAB/overrides on my Mac. I have e.g. ~/Documents/MATLAB/overrides/figure.m
Use startup.m to add overrides to your path with the warning turned off, and then turn it back on:
warning off MATLAB:dispatcher:nameConflict
addpath('/Users/victor/Documents/MATLAB/overrides');
warning on MATLAB:dispatcher:nameConflict
Not sure if tilde expansion works with addpath so I write the full path out.
Doing it this way suppresses the warning for me selectively only for the stuff that gets loaded from overrides. You can, of course, be even more selective with your folder naming. It also means I don't have to change anything in my MATLAB system files so it's localized to my user account and persistent across upgrades (for good or bad; monkey patch responsibly).
To access the built-in figure from my override, I have to cd there temporarily (as otherwise the override will simply call it self). So figure.m would look like this:
function fig = figure(varargin)
% Call original figure function
old = pwd;
cd(fullfile(matlabroot, 'toolbox', 'matlab', 'graphics', ''));
fig = figure(varargin{:});
cd(old);
% ...
% Do dirty override magic
end
I can't comment yet, so I'll just expand the answer given by vicvicvic further here. The general process stays the same, however it has some further fine tunings.
Put your override-function figure.m in a folder which is not on your current MATLAB path, e.g. /users/heidelberg/.matlab/_overload. For me, tilde expansion is supported, but I would not rely on it. However, you could also put it in a subfolder of a MATLAB startup script (see below).
Use startup.m to add your override folder to the path. To avoid the warning, make sure it is turned off, and then restore its original state
% save the current state while switching it off
warningState = warning('off', 'MATLAB:dispatcher:nameConflict');
addpath('/users/heidelberg/.matlab/_overload');
% restore the saved state
warning(warningState);
% cleanup
clear('warningState');
The difference here is that if e.g. your administrator set the warning to be off anyway, you won't accidentally switch it back on.
In your implementation of figure, at some point you will probably have to call the builtin version. vicvicvic suggested a cd to the directory, however there also is the MATLAB function builtin, which does that job for you:
function fig = figure(varargin)
% overload function
% call builtin figure
varargout = cell(1, nargout);
[varargout{:}] = builtin('figure', varargin{:});
% do you magic here
% ...
end
Also, use varargout and nargout to preserve for an arbitrary number of output arguments (might be irrelevant here and now, but for other functions or future releases it might be important).
Annotation
A method I prefer is to have a subfolder in the directory where my startup.m file is stored, called e.g. _overload. For me this is /users/timm/Documents/MATLAB/_overload. To easily add this folder, use the following script:
File /users/timm/Documents/MATLAB/startup.m
% extract the current directory (pwd can fail if started elsewhere)
[currentPath, ~, ~] = fileparts(mfilename('fullpath'));
% add the path, compare above
warningState = warning('off', 'MATLAB:dispatcher:nameConflict');
addpath([currentPath, filesep(), '_overload']);
warning(warningState);
% cleanup
clear('currentPath', 'warningState');
Adding a directory that contains the function overload to the search path will display the warning whenever a function in that directory is edited and saved, no matter if the directory is added in startup.m or not.
A simple way to solve this is to put overloading functions in a package. Then import the package in startup. No need to mess with warnings.