4.0

4.0 | 3 ratings Rate this file 11 Downloads (last 30 days) File Size: 4.14 KB File ID: #23124

Tip: calling subfunctions from outside m-file (Final)

by

 

26 Feb 2009 (Updated )

Calling/debugging subfunctions or writing large subfunctions is straight forward with this trick.

| Watch this File

File Information
Description

** Included is a skeleton file of the suggested trick. Type "myFunc" or "help myFunc" to see details shown below. **

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Bothering situations when you code in Matlab:

<< Case 1 >>

  If you extensively use the Matlab, you'll soon find that your project
  folder become full of small m-files. You may organize them in folders
  or you may incorporate similar functionalities in an object using OOP.
  However, sometimes, you just write some functions in a single m-file,
  though functions other than the one at the top can be called only
  within the m-file. This is perfectly fine because you usually expect
  these functions never be used by other m-files.

  Then, later, you find yourself wanting to access those small functions
  from other m-files. Now, you need to refactor those as individual
  m-files.

  That's pain. You just want to use it as it is. You don't want to make
  another m-file for that tiny function. Making a lot of such small
  m-files turns the folder mess like a big toy box. It becomes more and
  more difficult to find the one you want. You even just forget what you
  have.

  There are ways to avoid this pain (such as OOP as I already mentioned).
  But they want to suck your attention, planning, designing and so on and
  so forth. You want a real quick simple fix for it.

<< Case 2 >>

  You have an m-file that includes a few subfunctions. Initially, it
  was not a big deal. But as your project progress, the subfunction
  itself became pretty long. Then you found something wrong with it. You
  want to debug it. You mark some break points and run the top level
  function of the m-file. You step into the subfunction of trouble.
  You think you found something, modify a little bit, and save it, ...
  which makes you get out of the current context. You need to run the
  whole function from the start all again to get to that point. You don't
  want to run all of the main function again just to run that sub-
  function. It takes too much time and is cumbersome. You want to run it
  with a simple parameter right from the command window.

  Again, you decide to refactor the subfunction out of the m-file.
  Afterall, it became too big to co-exist with the main function in a
  single m-file. But then, it is not the only subfunction that you
  need to refactor. There are lots of them. Your project folder ends up
  like a trash can.

<< Case 3 >>

  You want to have an m-file that has several functionalities using a
  token. For example, if the token is 'A', the function do something. If
  the token is 'B', the function do something else. The problem is that
  'A' and 'B' requires different number of inputs/outputs. Worse, those
  inputs/outputs have very different meaning. Even worse, each of 'A' and
  'B' needs pretty long codes.

  Natual solution for this case is to use something like 'switch'.
  'switch' is a very simple good solution. But, because the meaning of
  inputs/outputs are different, the code reads very confusing. If each of
  'A' and 'B' requires long codes, then it is hard to find out where you
  are in the 'switch' statement.

  Again, refactoring each case as an individual m-file could be a good
  solution. But, sometimes (not often though), you need to use the same
  function name.

Solution: << My suggestion as a quick-fix >>

  Let's say the name of your m-file is 'myFunc', and there are several
  other subfunctions (mySub_A, mySub_B, etc) in the same m-file. Now you
  want to access "mySub_A" from outside. Then do the following two steps.

      1. Rename your top function (myFunc) to something else, such as
      'main' or 'myFunc_original', or whatever you want (I'll use
      'main').

      2. Add the following function at the top of your m-file.

          function varargout = myFunc(fid, varargin)
          if ~exist('fid','var')
               % add your default action for this m-file. Like...
               help myFunc
               disp('It needs a function name to call.');
               return;
          end
          fh = str2func(fid);
          [varargout{1:nargout}] = fh(varargin{:});

      Note that the function name should match the m-file name, which is
      'myFunc' in this case.

  Caution: There is one problem to this approach. You have to update all
  calls to the original myFunc like following.

      From
          [out1, out2, ...] = myFunc(param1, param2, ...)
      To
          [out1, out2, ...] = myFunc('main', param1, param2, ...)

  Now you can call any of your other functions in this m-file by running

      myFunc('mySub_A', a, b);
      [e, f] = myFunc('mySub_B', c, d);

  and so on. Inspect this skeleton file for more detail. (Read comments
  carefully.

<< END >>

MATLAB release MATLAB 7.1.0 (R14SP3)
Tags for This File   Please login to tag files.
Please login to add a comment or rating.
Comments and Ratings (7)
05 Jul 2012 M Sohrabinia  
08 Jan 2010 Stzpz ?  
28 Feb 2009 Sung Soo Kim

@us
Thank you very much for you comments. I learned a lot about mlint and regexp from your simple codes. I really wanted this kind of productive communication. Let me upload my 'hopefully' final version soon, which is also inspired by you too. :)

27 Feb 2009 us

you could use this engine to dynamically assign function handles to all 1.st level subfunctions in a file, which may return a variable number of output args

function fh=foo
x=mlint(mfilename,'-calls');
r=regexp({x.message}.','(?<=(S\d\s+\d+\s+\d+\s+))\w+','match');
r=[r{:}].';
for i=1:numel(r)
fh.(r{i})=str2func(r{i});
end
end
% subroutines
function varargout=msub(a,b)
r={
a-b
a
b
nan
};
varargout(1:nargout)={[]};
narg=min([nargout,size(r,1)]);
[varargout{1:narg}]=deal(r{1:narg});
end
function r=madd(a,b)
r=a+b;
end
function r=mmul(a,b)
r=a.*b;
end

% in the command window
fh=foo;
[a,b]=fh.msub(1,2)
% a=-1,b=1
[a,b,c,d,e]=fh.msub(1,2)
% a=-1,b=1,c=2,d=nan,e=[]

us

26 Feb 2009 Sung Soo Kim

@us
I tried your solution and found one negligible drawback, which is that you have to add each function's name in the top function and you have to make a handle in the command line whenever you want to use the function in a different namespace. This is still true when I use a class. But still I think your solution is more elegant because it does not use 'eval' which I don't like either.

26 Feb 2009 Sung Soo Kim

@us
Thank you for your fast reply. Your solution looks much better. I really appreciate it. I'll use it right away. Thanks for your time for reviewing my file.

26 Feb 2009 us

a better solution would be

function fh=foo
fh.msub=@msub;
fh.madd=@madd;
end
function r=msub(a,b)
r=a-b;
end
function r=madd(a,b)
r=a+b;
end

% in the command window
fh=foo; % load the function handles to the subfunctions
fh.msub(10,5)
fh.madd(pi,pi)

-and- once you start using r2008b+, you could simply implement all of this as a new class...

us

Updates
27 Feb 2009

No 'eval'. Super simple two line code snippet. Inspired by the comment of @us. Thanks to 'us'.

28 Feb 2009

Hopefully final version. Now it works for varargout as well.

01 Mar 2009

Hopefully final version. Very simple two line trick to access all subfunctions outside m-file.

02 Mar 2009

Final version. Just two lines of codes.

19 Jun 2009

copyright update

25 Sep 2011

codes were cleaned up. help was extensively updated.

Contact us