For example, I'd like to run something like
>> which_space_am_i_in()
and have it return 'base', or true, or something indicating the command-line workspace versus some workspace inside a function.
The basic functionality I'm looking for is I want a function to act differently depending if it's called from the command line (could be a script run from the command line) or from some other function.
Are there any builtin functions or simple ways to do this?
Check out dbstack.
--
Doug Schwarz
dmschwarz&ieee,org
Make obvious changes to get real email address.
Well, it's less elegant than I would've hoped, but I guess (length(dbstack)==1) provides a reasonable logical test. Thanks for the info.
Okay, I'll bite -- what's your use case? What should your function do
differently if called from the command line than if it's called from a
function?
--
Steve Lord
sl...@mathworks.com
comp.soft-sys.matlab (CSSM) FAQ: http://matlabwiki.mathworks.com/MATLAB_FAQ
function where
%The current location in the function stack
[s,wsi]=dbstack('-completenames') ;
str='In base workspace';
if length(s)>1,
str=s(2).file;
end
disp(' ');
disp([' ' str]);
disp(' ');
Well, isn't that a doozy of a question. At the end of this message, just remember: you asked :)
I'm in the process of hacking Matlab's builtin function representation (actually, I'm pretty much done). I'm a fan of the way Python handles things myself. Right now I've tweaked things with the packages I've written that I can do things like:
>> from finite_difference.matrices import central_second_order_matrix as d2
And this creates a function handle d2 in whichever workspace from which it's called. Unfortunately, I write lots of functions and frequently forget information about it (# of inputs, order of inputs, what the original function d2 was called, etc.).
To solve this, I've created a class FunctionNode, and each instance of FunctionNode corresponds to an m-file in a package. Now I've overloaded subsref for this object so that using function calling syntax, i.e. f(blah1, blah2), works exactly the same way as a function handle. However, going through Matlab's internal processing structure of overloading subsref appears to take a considerable amount of time (and my codes call lots of FunctionNodes multiple times). This is why the "from" statement only imports the function handle and not the entire FunctionNode instance -- for speed.
However, when I'm at the command line, I'd like to access my helpstring for a function imported using "from". I don't think I can do this using Matlab's implementation of a function handle. Sooooo, if I type a from statement at the command prompt or a script, I probably don't care about the extra time necessary to pass through subsref, but I DO care about helpstrings, function locations, etc. So at the command line I want to import the FunctionNode instance.
But inside a function, unless I'm debugging, then I have absolutely no need for helpstrings, etc., so I just want to import the function handle.
And all of this is just a way for me to create nice Python-like importing structures in Matlab so that I don't have to pollute namespaces with all of the bazillions of functions that I use (plus I create different functions with the same name...Matlab doesn't like that). I'm not aware of a clean way to do this in Matlab. (I don't like messing around with the PATH variable, and I am aware of Matlab's builtin import statement...I don't like it.).
Oh, and Matt J:
Thanks for the more in-depth implementation. I won't be needing this functionality in debug mode, so that's ok.
> And all of this is just a way for me to create nice Python-like importing structures in Matlab so that I don't have to pollute namespaces with all of the bazillions of functions that I use (plus I create different functions with the same name...Matlab doesn't like that). I'm not aware of a clean way to do this in Matlab. (I don't like messing around with the PATH variable, and I am aware of Matlab's builtin import statement...I don't like it.).
============================
Well, you said you don't like to mess with the path, but I'll just point you regardless to my FEX submission which does precisely that.
http://www.mathworks.com/matlabcentral/fileexchange/26221-namespace-scoping-operator
If you read the fine print, you'll see that there are some hazards, but the hazard is mainly if one of the functions you're trying to import is itself a path-manipulating function, which you say is already something you try to avoid.
Huh, that seems pretty snazzy. Obviously I don't understand the implementation yet, but it seems that it should be robust for most purposes. However, for me a big issue is speed (I run codes that collect many files from many different packages together). You do mention that path switching might be a little slow, and add this to whatever overhead is incurred by nesting things inside a class, and it might be too much for me.
Nevertheless, I'll probably download this and take a look-see. Thanks!
Well, keep in mind the alternative syntax shown in Example 2
newspace(Obj); %switches to temporary path
%do stuff
oldspace(Obj); %switches back to original path
The code in the "do stuff" section will execute under the temporary path with whatever speed it normally would in MATLAB. So, as long as these computations in that block are numerous enough or intensive enough that the CPU time is much longer than the time it takes to switch paths, the overhead due to path-switching will be 2nd order.
I don't know if that secnario applies to you...
Well, it turns out that such a scenario probably will apply to me. I certainly know that CPU time is significantly wasted if I overload subsref. I'll have to test it out to see if it applies when I change the path on the fly as well.
If I run
[s, index] = dbstack
at the command line, s has length 0 and index is 1. Fine.
If copy+paste that into a script and run it, then s has length 1 and index is 1. Fine.
If I copy+past that into a function and run it *from the command line*, then s has length 1 and index is 1. Fine.
If I run the aforementioned function *from a script*, then s has length 2 and index is 1. Not fine.
I want to be able to say from the last two instances that the workspace from which the function was called is the base workspace. I don't see how I can determine that from the given information of dbstack. How do I ask dbstack to tell me that the enclosing m-file is a function or a script? I don't think the "file" or "name" field of the struct s give me that information.
In particular, I don't understand what "index" is supposed to be. The help file for dbstack states that it's the "current workspace index". I cannot find any (other) reference to "workspace index" in Matlab's product help or from Google. So either dbstack does not really help me entirely,
Try nargin('junk'). If junk.m is a function it returns the number of
input arguments. If junk.m is a script you get an error.
By the way, are you familiar with packages in MATLAB? You can package a
bunch of functions in a directory named with a +. For example, if there
is a directory, '+mycode', on the MATLAB path and it contains fcn.m, you
call that function with
mycode.fcn()
and there is no conflict with any other fcn.m on your path. I know it's
not the same as Python and its import statement in that you have to use
the full package name, but maybe it's better than the non-standard
kludge you're working on now. Just a thought.
> By the way, are you familiar with packages in MATLAB? You can package a
> bunch of functions in a directory named with a +. For example, if there
> is a directory, '+mycode', on the MATLAB path and it contains fcn.m, you
> call that function with
>
> mycode.fcn()
>
> and there is no conflict with any other fcn.m on your path.
However, if inside mycode.fcn() a call is to be made to another function fnc2() which is also in the +mycode package, then it too must use the syntax mycode.fcn2() and so in with every function call. As well as being a cumbersome syntax, this means that, if you are given a library of mfiles that was not initially written as a package, it is very tedious to convert it. This is one of the main reasons I resorted to my FEX tool.
> To solve this, I've created a class FunctionNode, and each instance of FunctionNode corresponds to an m-file in a package. Now I've overloaded subsref for this object so that using function calling syntax, i.e. f(blah1, blah2), works exactly the same way as a function handle. However, going through Matlab's internal processing structure of overloading subsref appears to take a considerable amount of time (and my codes call lots of FunctionNodes multiple times).
===================
Even if that is true, by the way, it probably only means you are committing the classic MATLAB sin of trying to do a for-loop over computations that are better off being vectorized. For the overhead of going through subsref to be significant, the rest of the computations done by a single call to f(blah1,blah2) would have to be lightning fast. But we never do a loop over lightning fast function calls in MATLAB. We make one function call in a vectorized way.
Consider the following class, for example, which is essentially a subsref-driven function handle to the sin() function
classdef myClass
methods
function out=subsref(ob,S)
out=sin(S.subs{:});
end
end
end
Now take the data
X=rand(3000);
FancyHandle=myClass;
and compare the following timings. Essentially, there's no difference.
>> clear z, tic; z=sin(x);toc
Elapsed time is 0.287017 seconds.
>> clear z, tic; z=FancyHandle(x);toc
Elapsed time is 0.261119 seconds.
Hm, I'm afraid I don't follow your line of logic. If I'm inside a function, how do I use this to gather information about the number of input arguments in the caller? I suppose I could do something with an evalin statement by grabbing the function name from dbstack. However, as I mentioned before, with the Pythonic methods, I (often) rename function handles locally to names that are different from the function name inside the file -- I don't think dbstack will jive with this. And `nargin' run at the command line or in a script returns garbage (that could turn out to be an integer).
> By the way, are you familiar with packages in MATLAB?
Yes. But for the reasons Matt J specified (and others), I prefer not to use it.
> I know it's not the same as Python and its import statement in that you have to use
> the full package name, but maybe it's better than the non-standard
> kludge you're working on now. Just a thought.
You have a valid point about the Matlab packages functionality being built-in already. However, from my (admittedly biased) point of view, my method is much easier to work with and has serious advantages over Matlab's packages with few drawbacks (the current concern being one of them). The concern of the current thread is really quite ancillary and almost cosmetic.
"Matt J " <mattja...@THISieee.spam> wrote in message
> Even if that is true, by the way, it probably only means you are committing the classic > MATLAB sin of trying to do a for-loop over computations that are better off being
> vectorized. For the overhead of going through subsref to be significant, the rest of
> the computations done by a single call to f(blah1,blah2) would have to be lightning
> fast. But we never do a loop over lightning fast function calls in MATLAB. We make
> one function call in a vectorized way.
But it is not always possible to 'vectorize' code (e.g. if operations are inherently sequential). I always make pretty honest efforts to vectorize all code I write, but sometimes it's not possible (and sometimes it's not worth it). This happens often enough that I observe (significant) time penalties if I use a class instance to call a function rather than the handle directly. Besides, many of the codes I write do indeed perform fancy operations by creative uses of lightning-fast precompiled BLAS routines that drive Matlab's array backend; for moderately-sized arrays, the subsref call could double the required time. That's not acceptable to me.
And just as a comment: I'm not actually sure it's subsref that is the time restriction. It could just be that Matlab implementation of classes in general just isn't fast.
Ver y well. But then it's pretty clear that the overhead has nothing to do with MATLAB classes. It's simply because you've written subsref in M-code and all M-code execution is slower in general than C-code, not just class methods. You could have coded subsref as a MEX file, for example, and then it would have been nice and fast...
if isempty(evalin('caller','mfilename'))
%from command line
else
%from function or script
end
It will let you see if the caller is the command line or something else.
---
I'm also a fan of Python, but when in Rome... I handle this problem "the Matlab way", so I make some effort to differentiate variable names when they will be used in the same project.
To handle different projects with overlapping names, I think most people have an "init" script in each project that calls addpath repeatedly to set up all the needed folders (I've seen many files in the File Exchange with this system). This requires some effort on the user's part (type "init" at the console), but an easy way to make it more automatic is to change the "init.m" to be something like this:
if exist('initialized_project_xyz','var')
addpath abc
addpath def
...
initialized_project_xyz = true
end
Then "init" can be called at the beginning of all your main scripts, with negligible overhead. "addpath" already checks if you're adding a path that already exists, but is considerably slower.
I'm interested in this topic, so any improvement suggestion is very welcome :)
And by variable names, I obviously meant "function names"...
---
I also found a neat trick to group many small functions inside the same M-file, which may interest you as it allows you to reduce the number of files and thus have less folders to mess with. Put this in one M-file:
function some_module = get_some_module()
some_module.func_a = func_a;
some_module.func_b = func_b;
end
function func_a()
disp a
end
function func_b()
disp b
end
Now you can "import" all the functions in that group:
some_module = get_some_module();
And call them:
some_module.func_a()
some_module.func_b()
It's like an importable module in a single file; useful when you have a group of many small but related functions; or as a generic module if you don't mind having a rather large M-file.