A way to work around MATLAB's inability of put a local function into M-script
Show older comments
I have been wondering why we are not allowed to put a local function in a script file. According to related threads below, it seems that I am not the only one.
Down side of creating functions that are only to be used for a specific script might be...
- Names: If you keep doing this, your folder will be cluttered with lots of one-shot functions, and it is highly likely that you end up having lots of them with very similar and confusing names. Once you loose the track of record, you might not able to work out which function is right for you.
- Scope: Closely related to the above. Functions that are put in a folder are within the scope of all other files in the folder, or if the folder is in the MATLAB search path, of all the MATLAB files. Frequently used utility functions and those one-shot functions will be mixed up. Finding a right function may become more difficult with lots of other candidates with confusing names. Ideally, your one-shot functions should be only visible to the script that they were dedicated to.
- Maintenance: If you have to prepare five separate function .m files for one script, it would be more prone to loose their integrity, when copied to other place or people, for example. One-shot functions should better be kept in one place for maintenance.
I've been thinking about this, and came up with a very basic approach that can work around most of the above issues, albeit not entirely.
1. Use date-based sequential stem name for script file. A name like "scr2016_07_05_200000_xxxxx.m" may be beneficial, in that all the script and related files (html, mlx, pdf) will be shown in date order. It is easy to relate these sibling files. Also, it is useful to remember what you were up to on a specific day. Sequential numbering is a great way to avoid the pain of thinking of a unique name for just simple scripts.
2. Deploy a utility class with static methods. Create a classdef file with the name "scr2016_07_05_200000_xxxxx_util.m" Leave properties empty and put an attribute (Static) to methods as below. And then, you can add as many static functions as you want here.
classdef scr2016_07_05_200000_xxxxx_util
%scr2016_07_05_200000_xxxxx_util
properties
end
methods (Static)
function out1 = func1(var1, var2)
end
function out2 = func2(var3, varargin)
end
end
end
3. In your script, call an instance of "scr2016_07_05_200000_xxxxx_util" as below (Note you don't have to create an object to use Static methods. classname.staticMethodName(args,...) works. Below is just to avoid repeating lengthy class names.):
u = scr2016_07_05_200000_xxxxx_util;
4. Then, you can access to the static functions like this.
C = u.func1(A,B)
Benefit of this approach so far may be...
- Scope of those static methods are limited.
- You can find all of the related function in one place.
- You don't have to worry about thinking of absolutely unique function names every time. You only have to worry about uniqueness within the class, which is pretty easy.
- In essence, your script will have a twin brother of a dedicated utility class. I found that working on a .m or .mlx script and the classdef .m file side by side in one screen was extremely efficient. Your script will show abstract code on the left, and detailed workings in static methods in the classdef file on the right.

I'd like to hear your even better ideas or constructive feedback.
Thank you for reading.
Best, Kouichi
7 Comments
- If the one-shot function is not that complicated, then you could always use an anonymous one.
- You always have the alternative of making the script a function. It's just an extra line. There's no big difference between them and you can put as many one-shot functions inside it as you'd like.
EDIT
I should add that dynamic file names (that's what the date-based m-file names basically are) sound like a recipe for disaster and a bit of a nightmare for whoever is gonna be maintaining your code. This seems to be a prime example of what source control should be used for.
Guillaume
on 7 Jul 2016
I agree with José-Luis. make your script into a function. To boot, you get a cleaner workspace.
Or, you wait until the next version of matlab...
It seems that many learners start learning MATLAB by writing scripts, and only grudgingly move onto functions "when they have to".
When I started to use MATLAB I used only the command line (for trying things out) and by writing functions (main and local). Scripts just seemed such a messy way to write tidy code, I never even bothered with them. Now, millions of lines of code later, I still haven't written a script, and I don't miss them, and this topic never arises for me. Functions simply have so many advantages!
Looking at those three "down sides" listed in the original question, note that they are all elegantly solved by using functions (no scripts) and the inbuilt scope control tools:
- Names Local functions only need to be unique for each Mfile: every Mfile can use the same local functions names, if you so wish. No folder clutter either, with multiple functions in one Mfile!
- Scope Local functions, private functions, packages, path,... there are plenty of ways to control scope.
- Maintenance "If you have to prepare five separate function .m files for one script..." yep, so instead just create one Mfile with six functions. Oh, the problem just disappeared!
EDIT: Oh my, that "dynamic function" idea... Wow... that is really a asking for obfuscated and buggy code! Why not just stick to the inbuilt ways of defining namespaces: local functions, private functions, packages, etc. Reinventing the wheel might be a fun game, but it only makes that code more complicated, non-standard, impossible to distribute, and much harder to maintain.
Kouichi C. Nakamura
on 7 Jul 2016
José-Luis
on 7 Jul 2016
Well... even that top level script can be a function without arguments that calls all you need. I don't understand the issue.
I am not sure I agree with you regarding the suitability of messy code.
Kouichi C. Nakamura
on 7 Jul 2016
This is deviating quite a lot from the original question, but anyway the way I usually cope with this sort of top level function/script that may need restarting in case of issues/crash/abort is to actually use a class. This has several advantages:
All the default constants that you would define in your scripts, they can just be the default values of the properties of your class.
If the user wants to modify some of the constants. Easy, just change the given properties.
You can save the object to a mat file, so that you have a record of the settings used without needing to modify the source code. Good for version control. You need to reprocess the data with whatever settings you used a year ago. Reload the object from the mat file.
You can have a method that starts the processing from the beginning and a similar method that resumes from where it left off.
E.g.:
classdef DropSizer < handle
properties (Access = public)
SizeThreshold = 20;
EdgeWidth = 10;
%...
end
methods
function Run(this, imagelist)
state = struct('ImageList', imagelist, 'CurrentIndex', 0);
this.Process(state);
end
function Resume(this, resumestate)
this.Process(resumestate);
end
end
methods (Access = Private)
function Process(this, state)
%processing may take a long time and crash
while state.CurrentIndex < numel(state.ImageList)
currentimage = state.ImageList(state.CurrentIndex + 1);
%entering procedure that may error
try
%do something
catch exception
fprintf(2, '<strong>While processing image index %u</strong>:\n', state.CurrentIndex + 1);
fprintf(2, '%s\n', exception.message);
assignin('base', 'resumestate', state); %store in base workspace or you could save to mat
return;
end
state.CurrentIndex = state.CurrentIndex + 1;
end
end
end
end
My functions are actually function objects which I find a lot neater when you want to deal with optional inputs (they're properties with default instead).
Accepted Answer
More Answers (2)
Steven Lord
on 15 Sep 2016
1 vote
Release R2016b is now officially available. As listed in the first item in the Language and Programming section of the Release Notes for MATLAB in that release, you can now define local functions in script files.
1 Comment
Kouichi C. Nakamura
on 15 Sep 2016
Kouichi C. Nakamura
on 15 Aug 2016
0 votes
Categories
Find more on Profile and Improve Performance in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!