Loren on the Art of MATLAB

Turn ideas into MATLAB

This is machine translation

Translated by Microsoft
Mouseover text to see original. Click the button below to return to the Original version of the page.

What Kind of MATLAB File is This? 15

Posted by Loren Shure,

We just had an interesting thread at MathWorks prompted by a customer request to programmatically distinguish between script and function MATLAB files. The File Browser already shows these separately. I will show some ideas we had and what we agreed was a good way to attack this.

Contents

Function Vs. Script: The First Idea

The first idea was to create a function, perhaps called isfunction, and might be implemented by opening and reading the file, and looking for a function signature. Of course, you'd need to be sure that the function signature was not embedded in a comment. The tedium of doing this struck me and led me to ...

Function Vs. Script: The Next Idea

The next thing I thought of was to see what the function nargin did with various files on my path. I encourage you to read the documentation for this function. It's not very long.

Let's first see what happens for a "typical" function.

maxInputs = nargin('fftshift')
maxInputs =
     2

We see that nargin finds that fftshift is called with up to 2 inputs.

Now let's try a function that can have any number of inputs.

maxInputs = nargin('ndgrid')
maxInputs =
    -1

Here, the negative value indicates that you can input a variable number of inputs, and the first formal input is varargin.

If I were to try a script, e.g., this one, here's what I would type

    nargin('whatIsThis')

And here's the output from the command window.

  Error using nargin
  whatIsThis is a script.
  Error in whatIsThis (line 31)
  nargin('whatIsThis')

We get an error message for this case. If we want to write a program to determine the file type, we can't have the program error out. So, in order to robustly check to see if the file is a function, we need to plan for scripts. For that, I recommend using the try/catch construct.

try
    maxInputs = nargin('whatIsThis')
catch exception
    if strcmp(exception.identifier, 'MATLAB:nargin:isScript')
        disp('This file is a script.')
    else
        % We are only looking for scripts and functions so anything else
        % will be reported as an error.
        disp(exception.message)
    end
end
This file is a script.
try
    maxInputs = nargin('blogTopics.doc')
catch exception
    if strcmp(exception.identifier, 'MATLAB:nargin:isScript')
        disp('This file is a script.')
    else
        % We are only looking for scripts and functions so anything else
        % will be reported as an error.
        disp(exception.message)
    end
end
Not a valid MATLAB file.

So now we can identify scripts without causing an error.

What about Classes?

There's another kind of code file in MATLAB, pertaining to classes (the updated style, since R2008a, where classes are defined with (https://www.mathworks.com/help/matlab/ref/classdef.html classdef>), and we haven't done anything special to see if the file in question is for a class. I will demonstrate with the class dataset from Statistics Toolbox.

maxInputs = nargin('dataset')
maxInputs =
    -1

The fact that dataset can take a variable number of inputs doesn't tell us that dataset is a class file. To probe for that information, we can use the function exist. Looking at the help, we see that if the file in question is a class file, then exist returns the value 8. To ask specifically if it's a class, we use this code.

classy = exist('dataset','class')
classy =
     8

To be sure the files we probed originally are not class files, we need to check them out as well.

classy = exist('fftshift','class')
classy =
     0
classy = exist('ndgrid','class')
classy =
     0
classy = exist('whatIsThis','class')
classy =
     0

Do You Need to Distinguish File Types in Your Work?

Do you have a similar need, where you need to characterize different file types, not based on their extension (e.g., .m)? I'd love to hear about cases where you need similar functionality. Let me know here.


Get the MATLAB code

Published with MATLAB® R2013a

Note

Comments are closed.

15 CommentsOldest to Newest

Nathaniel replied on : 1 of 15
A slightly related topic is finding the name of the currently executing mfile. I've used this a lot for ensuring that an automatic copy of a script can be saved every time it is run, along with the results it produces. This is useful when the file controls a measurement or simulation, and one wants a record of all the parameters and control flow, in case of later suspected problems. The mfilename command comes in useful: myname = [ mfilename('fullpath'), '.m' ]; The use of nargin to analyse a function file (instead of using it only within a function) was new to me. I don't remember offhand having a need, but I'll try to remember it. Finding what a file actually is (regardless of name) is important when recovering corrupted filesystem data. unix(['file ', filename]) The GNU "file" command is pretty good on its heuristics and detail. Perhaps Matlab could implement a "file" or "filetype" or "aboutfile" command, that would at least give details about all matlab recogniseable files (e.g. m-file script or function, number of arguments, mex file, hdf5-based figure, v5 mat-file etc etc) and preferably others too (text:ascii, text:utf8, pdf, etc).
Alfonso replied on : 2 of 15
That was very interesting. One minor question: if I am correct, the function 'exist' only checks for classes that are on the current path, but it can not be used in conjunction with a fullpath (e.g. exist('./myfile.m','class') returns 0 even if myfile is a class definition file; similarly exist('./myfile.m') returns a 2 even if myfile is a class definition file). This, of course, creates some issues when trying to identify class definition files if one needs to discriminate among multiple files sharing the same name. So I am curious, is there some workaround for this?
Loren Shure replied on : 3 of 15
Alfonso, Yes, exist only identifies classes that MATLAB can create at that time. You need the file in question to be accessible in MATLAB before it can be identified as a class. So be sure you have the right path. --Loren
Loren Shure replied on : 4 of 15
Nathaniel, You are right that there is not one command alone that can identify the MATLAB files. A short combination of commands could be put together, as I have shown in this post, to get the information. Can you please say more about why you want one encompassing function and when/how you would use something like that? --Loren
adam replied on : 5 of 15
I haven't had the need yet myself to test whether a file is a script or a function (I often find myself converting scripts to functions anyway to tidy keep variable scope constrained), but I recently wrote functionality testing if something is a class or function. We are trying to use the Matlab unit testing framework more and more and I have been writing some functions/scripts to wrap up some functionality to make it easier for members of our team who are unfamiliar with it. One of these functions is a 'createUnitTest( myFile )' function which I can just call with the class/function I have just written as argument and it will create a template with the various unit test setup/teardown/test fixtures and the inheritance from matlab.unittest.TestCase - i.e. the things that are easy to forget and put off team-members unfamiliar with the test framework from writing a test when they are in a hurry. This function does a number of things, determining where in the file tree top create the new file, etc, but it also creates a different template depending whether the file in question is a class or function in an attempt to make process of creating unit tests as painless as possible. This framework of 'helper' functions also makes use of what Nathaniel mentioned, using the path of the currently executing m-file to recursively build up test suites and similar functionality.
Mark Brown replied on : 6 of 15
Here's a rather obscure solution using some functions that still ship with Matlab (as of R2013a). tree = mtree('classfile.m','-file'); tree.select(1).kind will return the character string: ans = CLASSDEF tree = mtree('functionfile.m','-file'); tree.select(1).kind will return the character string: ans = FUNCTION tree = mtree('scriptfile.m','-file'); tree.select(1).kind will return the character string: ans = EXPR or some other string (other than FUNCTION or CLASSDEF). MTREE is a great function that I use to parse m-files to look for file dependencies. It's fast and works much better than any other utility out there. I hope TMW doesn't deprecate it. Experiment with it!
Loren Shure replied on : 7 of 15
Thanks, Mark. For the benefit of others, mtree is not a documented MATLAB function. Just be aware of that if you depend on it. --Loren
Mario Lietz replied on : 8 of 15
My last function I committed to matlab fileexchange also distinguishes between script, function and class files. I simply count the number of functions that are defined within the file. I can do so, because I need all functions anyway. This is a little tricky, but with a search for regular expressions quiet fast. Therefore I compare all beginning of lines with the string „function“ txt_new = strtrim(txt); function_pos = strncmp(txt_new,'function ',9); Furhtermore, one must look for every function_pos if it is really a function with: txt = txt(10:end); funName = strtrim(regexprep(txt,'\(.*.*|\%.*','','once')); funName = regexp(name,'((\w)*\.)?(\w)*$','once','match'); If the file contains no function, it's a script file. Otherwise it’s a function or class file. To distinguish between these latter two I used the function: exist(filename,'class') . Why I look for the function names you can see here: https://www.mathworks.com/matlabcentral/fileexchange/43198-embeddedmethodsviewer-show-functions-and-methods-within-matlab-editor
Loren Shure replied on : 9 of 15
Adam- Thanks for explaining your workflow. Mario- Thanks for sharing your algorithm. --Loren
Jim Hokanson replied on : 10 of 15
Mark, Have you posted your parsing solution somewhere that I could look at it? If not would you be willing to send it to me? gmail: jim.hokanson Thanks, Jim
Yair Altman replied on : 11 of 15
@Jim - Mark's comment refers to an internal m-file function (or rather, a class) that is included in Matlab releases and exists on the path (%matlabroot%\toolbox\matlab\codetools\@mtree\mtree.m). As Loren noted, this is not a supported function, and so it might go away in a future release. But as of today we can still enjoy this wonderfully complex class (3K+ lines). The file is heavily documented internally, and you're welcome to look at it. I plan to write a post about it some day. - Yair
Jim Hokanson replied on : 12 of 15
@Yair, Thanks. Just to clarify, I actually was hoping to get the code Mark used to look for file dependencies. Unless I am missing something in mtree I am guessing it isn't much better than fdep. Unfortunately fdep has some bugs. I'm working on rewriting it using much more explicitly defined mlintmex calls than Urs used, but I always welcome someone else's solution to the problem. Jim
Amro replied on : 13 of 15
This came up on Stack Overflow a few months ago: http://stackoverflow.com/questions/15910210/distinguish-between-scripts-and-functions-programmatically All three solutions mentioned above were suggested: - manually search file content for a function signature - use nargin - use mtree to build parse tree Even though |mtree| is undocumented, it is the same function being used on Cody to score solutions. It was also used in the MATLAB online contest.
Mark Brown replied on : 14 of 15
In response to a request by John Hokanson, I have posted my routine for finding file dependencies on The FileExchange. It should be available in a few days.
Jamie replied on : 15 of 15
I have an application where I am trying to determine all the functions associated with my MATLAB installation. I use the list for syntax highlighting in a text editor. With my upgrade to R2013a I found that my approach was picking up scripts so I did some poking around and was pointed to this post. I was interested to see the differences between the approach proposed here by Loren, the mtree approach, and stackoverflow solution (http://stackoverflow.com/questions/15910210/distinguish-between-scripts-and-functions-programmatically). So I applied each to a special case, mcc. It has an m-file but is linked to a mex file. Loren's approach: "mcc does not know how to answer nargin/nargout" mtree approach: "mtree (complete: 0 nodes)" stackoverflow approach: "ans = 0" (input is a function) Loren's and stackoverflow approaches give similar results but the latter picks up a few more functions like mcc, dataread, etc. that I would like to pick up for my application.