I'm trying to understanding scoping within Matlab and I'm a bit confused. From what I have gleaned from the internet I know that if a variable is defined in the primary function the nested function will see that variable in its workspace. For example
function test = myfun(x)
a = 1;
function test = myfun2(x)
test = x + a;
end
test = x + myfun2(x);
end
>>myfun(1)
3 #Yay it worked.
However, if I break myfun and myfun2 into separate .m files I get an error. For example
myfun.m
function test = myfun(x)
a = 1;
test = x + myfun2(x);
end
myfun2.m
function test = myfun2(x)
test = x + a;
end
>>myfun(1)
Undefined function or variable 'a'.
What is up? I have attempted to make a a global variable in the myfun.m file, however, this did not change matters. The only way I can get around this is if I include a as an argument in myfun2 which is something I would not like to do.
Each function in MATLAB has it's own local scope (or workspace as MATLAB calls it) consisting of the variables that you define within that function. The function can only see these variables and does not have access to variables stored within other functions or the base workspace.
You are correct that a nested function has access to the workspace of the parent function which is why your first example works. When you create a separate m-file, however, myfun2 is no longer a nested function. It is a stand-alone function with it's own isolated local scope.
The only (recommended) way of sending information between the various local scopes of the functions is via input and output arguments to the functions. The use of global variables is discouraged.
So for these two separate m-files, you would need to define input and output arguments for myfun2 like the following.
myfun.m
function test = myfun(x)
a = 1;
test = x + myfun2(x, a);
end
myfun2.m
function test = myfun2(x, a)
test = x + a;
end
Then you can call myfun as you expect.
>> myfun(1)
If you really must use globals, then you need to define the global variable within all workspaces that need access to it. So you would want to place the global a statement in both functions.
Related
Maybe it's a basic question but here I go. I would like to have a .m with all the functions that will be accessed by other scripts and functions.
I tried just doing a script with all the functions and call it in other functions code.
And I got and error. Could you please explain me how can I solve this?
I'm trying this, which gives me no error, and does what I want it to do, still, is it a good way to do it? Any suggestions?
function PruebasLlamaFuncion
funcionFEM=#PruebasTodasFunciones;
a=funcionFEM('OVERPOWER',1,5)
b=funcionFEM('POWEROVERWELMING',2)
end
...
function a=f(nombre,varargin)
f=str2func(nombre)
a=f(varargin{1:end});
end
function d=OVERPOWER(J,c)
d=J*c;
end
function e=POWEROVERWELMING(J)
e=J;
end
Function placement
Matlab, unlike a number of other languages, permits a single file to contain only one main function that is visible to the rest of the system. The main function is the first function. (Documentation)
Any functions that are defined after the main function body are called local functions. These functions each create their own separate workspace (scope) and can be called by one another and, of course, by the main function.
Any functions that are defined within the main function body are called nested functions. These functions have their own workspace but are also able to access and change the variables of their parent function under certain conditions. Nested functions at the same nesting level can call each other and local functions, but local functions cannot call nested functions since they are out of scope.
Workarounds
There are several options available to you depending on how you would like to proceed.
At the risk of giving too many options but desiring to be exhaustive, I'll put the list from what I would do first to what I would do last.
For most things, I would recommend 1 or 2.
The other options are more for creating libraries/APIs, but I included them to show what can be done.
Define Function1 and Function2 in separate m-files on the Matlab path or in the present working directory to call them normally.
Wrap the main body of your work (the one calling the functions) in a function itself and define the other functions as local functions or nested functions. Example:
function output = main(a,b,c)
Result=Function1(a,b,c);
Result2=Function2(b,d);
...
% You can define Function1 and Function2 here for nested functions
end
% Or you can define Function1 and Function2 here for local functions
You can get a bit more fancy and have a function that returns function handles (pointers) to the local or nested functions and then use the (in the example) struct to call the functions in another script:
function Functions = GetFunctions()
Functions.F1 = #(a,b,c) Function1(a,b,c);
Functions.F2 = #(a,b) Function2(a,b);
% You can define Function1 and Function2 here for nested functions
end
% Or you can define Function1 and Function2 here for local functions
If you have R2013b or above, you can do the same thing as above using the localfunctions function to create a cell array of handles to all local functions (in this case, the definitions are required to be outside the main function body).
function Functions = GetFunctions()
Functions = localfunctions(); % R2013b+ only
end
% Define Function1 and Function2 here for local functions
You can also create a class with static functions:
classdef Functions
methods(Static)
% Define Function1 and Function2 here and call them just like the struct above.
end
end
I hope that makes sense and hopefully helps.
I think you're misunderstanding something. A script is for calling a series of functions/other scripts in sequence. If you just want your functions to be accessible in other code, you only need to make sure they're on the path. You would never need a "script containing all the functions". You may be thinking of local functions, but these are the exact opposite of what you want (they can't be called from outside the function where they're defined or other local functions in the same file).
e.g. if Function1 and Function2 are on your path, you could write a script like this, perhaps as a demo for how to use those two functions:
a = 0;
b = 1;
c = 2;
d = 'Unicorns';
Result=Function1(a,b,c);
Result2=Function2(b,d);
It does not and should not have any function definitions in it. If your script can't find the functions, use addpath (see docs), to put the folder where these function files reside into your path. The m files should be given the same name, e.g. the following needs to go in a file called myfunc.m
function result = myfunc(a,b,c)
Functions in your working directory can also be called even if that directory isn't on your path.
I have written a function to perform permutations of n obejects.
I have the variables a=[1],[2],[3];k=1 and n=4;a contains the objects which are 1,2 and 3 respectively.The following is the function code that i have written:
function [res]=perm(a,k,n,jj)
if k==n
res{jj}=a;
jj=jj+1;
else
for i=k:n
t=a{k};
a{k}=a{i};
a{i}=t;
perm(a,k+1,n,jj)
t=a{k};
a{k}=a{i};
a{i}=t;
end
end
end
However, when i call the function as:
jj=1;
[res]=perm(a,k,n,jj)
I am getting the following error displayed:
Error in ==> perm at 3
if k==n
??? Output argument "res" (and maybe others) not assigned during call to "J:\main
project\perm.m>perm".
Error in ==> mainp at 254
[res]=perm(a,k,n,jj)
The following is the code in the main program with regard to the permutation:
mr=4
for i=1:mr
a{i}=i;
end
n=mr;
%This assignment is for the ease to work with.
%just stored the indices till mr for the purpose of permutation
k=1;
%this is the k that the function perm has
jj=1;
[res]=perm(a,k,n,jj)
Can somebody please help me resolve this?Thanks in advance.
Your else block leaves res undefined.
I think you're assuming that res is a global variable and all invocations of perm will write into different parts of a single cell array. That isn't true. It is an output variable, local to the current call. There's no sharing during recursion, they all have independent cell arrays named res. The parameter jj is also not shared, so adding one is useless as well.
If you want to use this technique of building up the output, you'll need to make sure it is defined at a wider scope than the recursion. For example, use a local helper function:
function [res]=perm(a,k,n,jj)
res = {};
perm_impl(a,k);
function [] = perm_impl(a,k) // doesn't get its own local res, n, or jj
if k==n
res{jj}=a;
jj=jj+1;
else
for i=k:n
t=a{k};
a{k}=a{i};
a{i}=t;
perm_impl(a,k+1)
t=a{k};
a{k}=a{i};
a{i}=t;
end
end
end
end
Now all runs of perm_impl work on the same cell array res, because Matlab documentation says:
Variables within nested functions are accessible to more than just their immediate function. A variable, x, to which you assign a value or use within a nested function resides in the workspace of the outermost function that both contains the nested function and accesses x.
If you intentionally use a variable in this manner, it is not a problem. For examples, see the MATLAB Programming Demo on Nested Functions.
However, if you unintentionally use a variable in this manner, it can result in unexpected behavior. If the highlighting indicates that the scope of a variable spans multiple functions, and that was not your intent, consider:
Renaming the nested function variable so it does not match the outer function variable name.
Passing the variable into the function as an input argument instead of using the variable directly within the nested function
I can't tell whether a was supposed to be shared or not...
Suppose I want to declare some variables then declare a function:
x = 2;
function y = function(x)
y = (x^2)+1;
end
y = function(x);
disp(y)
Matlab returns the error "Function keyword use is invalid here..."
Why can't I declare variables or write any text before declaring a function? Is there good reason or is it a quirk?
EDIT:
To clarify, I do know how to get around this problem (but thanks for the suggestions nonetheless) but I suppose I'm asking why the Matlab team made this decision. By making a function declaration the first line of a file, does it have implications for memory management, or something?
The REPL prompt of Scala can have a function defined after a variable. So this is a choice (a quirk if you want) from Matlab's inner internals.
If a function is defined in a file, there are two possibilities:
The main function of that file. Then the file must begin with the function declaration: in your example, function y = fun(x). I'm using fun as the function's name. I don't think function can be used as a function's name.
See here for more details.
A nested function. In this case, the function declaration and definition can be within another function of the preceding case.
See here for more details.
As you can see, in either case the file begins with a function declaration (namely that of the main function).
The function can also be defined as an anonymous function. Then no declaration is needed, and the function can be defined anywhere. But there's a restriction: the function can contain only a single statement (so it cannot define internal variables other than the output). Therefore this method can only be used for simple functions.
In your example, the function could be defined anonymously as fun = #(x) x^2+1.
See here for more details.
Others have given good info about nested functions and such.
But the reason for the error you get is that "function" is a reserved word in Matlab. You cannot have a function with this name.
function y = my_function(x)
y = (x^2)+1;
end
And stick it in another file called my_function.m
I have a file funcs.m that stores anonymous functions. They must be usable by the files in the directory where it is. Currently, I use the anonymous functions so that I execute the file funcs.m in different files but I think this is a a wrong way of doing things. The other functions such as main.m and its nested function nest.m need to use the anonymous functions from funcs.m. I think paths won't solve this problem because the files are in the same folder. Basically I could solve this problem by copy-pasting the anonymous functions to every file but code-smell so:
Is there some way of reusing the funcs.m having the anon functions in Matlab?
Example
main.m
function main
funcs; % loads the anonymous functions
nest(par1,...,parN)
end
nest.m
function nest(par1,...,parN)
funcs; %ERRR: This fires err, why? Look: this was sourced already in main.m!
function neededOnlyHere(par100)
bq(q,A) %This needs the functions of the funcs
end
neededOnlyHere(somePar) %ERR to use the anon funcs from funcs
end
Functions main.m and nest.m use this function funcs.m having the anonymous funcs
bq=#(q,A) q*A; %Bolded q
I=#(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0);
AiNotj=zeros(1,Ncut);
...
ERROR
Attempt to add "bq" to a static workspace.
See MATLAB Programming, Restrictions on
Assigning to Variables for details.
Error in funcs (line 10)
bq=#(q,A) q*A;
%Bolded q
Why it's breaking
You get the error when calling it in nest.m because having a nested function makes its enclosing function's workspace a "static workspace"; that is, variable names cannot be added via eval(), assignin(), or other "dynamic" techniques; only variables that are explicitly assigned in that function's text are allowed. Evaluating a script to define local variables - which is what you're doing when calling funcs.m - is "dynamic", so prohibited in functions with nested functions. It works in main.m because main has no nested functions and is thus a "dynamic" workspace.
There are a couple ways you could change it to work with static workspaces and nested functions. The first thing to ask is whether you really need to make them anonymous functions?
Using package functions instead
If you don't need them to be anonymous functions per se, just break them out and put each one as a regular function in its own .m file; e.g. bg.m, I.m, AiNotj.m, and so on. Then they're all available to all other functions in that directory.
If that turns in to a mess of files, or if you want to scope them and maybe make them available only to the selected functions that really need them (that is, the functions currently calling funcs()), then you can stick them in a package. Create a subdirectory called +myfuncs and move all the little function files in there; e.g. +myfuncs/bq.m, +myfuncs/I.m, +myfuncs/AiNotj.m. (The + prefix tells Matlab the directory is a package.) Then you can pull all of them in to your function scope by doing import myfuncs.* as a direct replacement for where you're currently calling funcs().
function nest(par1,...,parN)
import myfuncs.*;
function neededOnlyHere(par100)
bq(q,A) % This will work, resolving to myfuncs.bq
end
You can do the import myfuncs.* from the command line to make them available interactively, too.
This is probably how Matlab itself wants you to organize clusters of related functions like this, and would be my first approach. It's the least "smelly" IMHO. If you really wanted to be able to edit them all in a single file like funcs.m for convenience, you could write a little code munger in Perl or whatever that parsed funcs.m and output them all as equivalent individual functions as a preprocessing step. (I think it's a bit of a bummer that you can't define multiple top-level functions in an M-file like this, but oh well.)
If you really need to work with anonymous functions, there are some workarounds.
Passing functions in a struct
You can change your funcs() function to actually return a struct of all those anonymous functions, using field names instead of local variable names.
function out = funcs
out.bq=#(q,A) q*A; %Bolded q
out.I=#(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0);
out.AiNotj=zeros(1,Ncut);
For this, you'd have to prefix all the function references with the struct name you're holding them in. Don't know how big a deal this is for you.
function nest(par1,...,parN)
fs = funcs;
function neededOnlyHere(par100)
fs.bq(q,A) %This needs the functions of the funcs
end
Preallocating variables
To get funcs() to work as-is, you can statically pre-allocate variables with all the function names you're going to use, so the Matlab parser recognizes them as statically assigned variables. Then when you call funcs(), it will re-assign the values of the existing variables, which is permissible in dynamic workspaces.
function nest(par1,...,parN)
[bq, I, AiNotj] = deal(); % Preallocate all names from funcs
funcs;
function neededOnlyHere(par100)
bq(q,A) %This needs the functions of the funcs
end
This would be a bit of a pain, because you'd have to re-edit every file that uses funcs whenever a new function name is added. You could at least write a little perl script to auto-generate that line of code by parsing funcs.m and outputting a "[bg, I, AiNotj,...] = deal();" with all the functions it finds, and you can just copy that in to your code.
Another way to do this would be to have funcs actually return all the functions in its output list. This would have the benefit of continuing to work even as you add new functions to funcs.m, as long as you don't remove or change the order of your existing anonymous functions.
function [bg,I,AiNotj] = funcs()
bg = ...
I = ...
% And then in the calling functions:
[bg,I,AiNotj] = funcs(); % which you can copy and paste from funcs.m's header
There are many ways of passing anonymous functions:
1) Pass the function itself:
function main
f = #(t) t^2 - 3;
param = randn(12,1);
g = test22(param,f);
disp (g)
end
function g = test22(param,f)
g = f(param(2));
disp(param(2))
end
2) Use globals (which usually should be avoided in complex code)
function main
global f
f = #(t) t^2 - 3;
param = randn(12,1);
g = test22(param);
disp (g)
end
function g = test22(param)
global f
g = f(param(2));
disp(param(2))
end
Is there a quick way (i.e. one line) to dump a collection of variables "in" a structure, using the variable names as the structure fields? The "load" function basically does this but saving and loading to a temporary file seems ugly.
For example:
clear
a = 'adsf'
b = rand(10);
x = var2struct(a,b)
x.a
x.b
or better yet:
x = var2struct(['a';'b'])
Also, what about the reverse (i.e. dumping the field values to the current scope as variables named after the fields)?:
clear
x.a='asdf'
x.b=rand(10);
dumpstruct(x)
a
b
Also, here's a related newsgroup thread.
Aside from using LOAD and SAVE, there is no built-in function that I know of to do this. However, you could just make your own functions, like so:
function s = var2struct(varargin)
names = arrayfun(#inputname,1:nargin,'UniformOutput',false);
s = cell2struct(varargin,names,2);
end
function struct2var(s)
cellfun(#(n,v) assignin('base',n,v),fieldnames(s),struct2cell(s));
end
Working from the base workspace, you can use these functions like so:
a = 'adsf'
b = rand(10);
x = var2struct(a,b);
clear a b
struct2var(x);
A couple notes:
If you would rather specify the arguments to var2struct as the variable names instead of the variables themselves, here is an alternative function:
function s = var2struct(varargin)
values = cellfun(#(n) evalin('base',n),varargin,'UniformOutput',false);
s = cell2struct(values,varargin,2);
end
And you would use this from the base workspace as follows:
x = var2struct('a','b');
Unfortunately, you can only use this version of the function to get variables from the base workspace, not the workspace of a function.
One caveat with the struct2var function above is that it will always create the variables in the base workspace, not the workspace of the function calling struct2var. To create variables in a workspace other than the base, you would have to use this line in that workspace instead of calling struct2var:
cellfun(#(n,v) assignin('caller',n,v),fieldnames(x),struct2cell(x));