I am trying to modify a structure array from within a nested function, where the nested function is 'returned' through a function handle. From what I know, you cannot modify the structure array from the 'outer' function, since MATLAB pass arguments by values and not by references. However, you should be able to do it from within a nested function as the nested function can access the 'parent' scope. However when I 'address' the function using function handle it does not work.
Here is the code:
function object = objectReader()
object.counter = 0;
object.getData = #GetData;
function data = GetData(input)
object.counter = object.counter+1;
data = input*1.23456789;
end
end
From what I found, it could be that when making the function handle, it also makes a copy of the 'current' scope so the function since than lives in 'isolated environment'.
So the question is, how can I do modify a structure array from within a nested function, while maintaining the outside interface? By outside interface I mean that you can do:
object = objectReader();
data = object.getData(1);
and object.counter increments each time you call object.getData() function.
Add to your example the counter as output and you will see the increments:
function object = objectReader()
object.counter = 0;
object.getData = #GetData;
function data = GetData(input)
object.counter = object.counter+1;
data = [input*10 ,object.counter];
end
end
And the example:
myobject = objectReader();
disp(myobject.getData(1)); % 10 1
disp(myobject.getData(1)); % 10 2
Read more about closure here:
https://research.wmz.ninja/articles/2017/05/closures-in-matlab.html
And it is more natural to do it using class with properties and methods: https://uk.mathworks.com/help/matlab/matlab_oop/create-a-simple-class.html
Related
I've got the following class
classdef setting
properties(Constant)
n = setting.get_n;
q = setting.get_q;
end
methods(Static)
function data = load_setting
File = 'Configuration.ini';
I = INI('File',File);
I.read();
data = I.get('UserData'); % struct
end
function n = get_n
data = setting.load_setting;
n = data.m + 2;
end
function q = get_q
data = setting.load_setting;
temp = data.q;
q = fieldnames(temp);
end
end
end
I'd like to know if it is possible to access data returned by load_setting automatically in the rest of the methods defined in the class instead of calling it data = load_setting in each method. Suggestions will be really helpful.
Constants are typically provided by functions in MATLAB. For example, pi is a function. A function that provides constant data that is read from a file could be written like this, using the keyword persistent (code not tested):
function data = config_data
persistent data;
if isempty(data)
File = 'Configuration.ini';
I = INI('File',File);
I.read();
data = I.get('UserData');
end
end
Now the first time you use config_data, it will load the data. Subsequent times it will immediately return the data struct. In the most recent version of MATLAB you can use dot indexing on the return value of a function, so you can do config_data().m or config_data().q and get the relevant field from your data. The function above could process the data further to obtain the q and n values that are computed in your static class methods, so you don't need anything from the setting class, as long as all the data is static.
If you need your constant data to be a class instead of a function (static methods computing values on the fly, or using input values), I would plug the above into your class as the static function load_setting, because that leads to the least amount of work.
there is a way to create a Constant property which you can change it! its through class composition.
first you should define a data class of reference(handle) type :
classdef dataclass<handle
properties
m=3;
n=4;
end
end
then create a Constant data property in your setting class :
classdef setting
properties (Constant)
data=dataclass()
end
methods (Static)
function somefunc()
a=setting();
a.data.n=1;
a.data.m=2;
end
function out=showdata()
out=setting.data;
end
end
end
this way you have a constant reference to the data and when you call A.somefunc() you can change it within all class and all objects of that class.
I have a function defined like the following in a .m file:
function main_fn()
...
end
function sub_fn1()
...
end
function sub_fn2()
....
end
...
function sub_fnN()
...
end
i.e. standard structure with main function first followed by subfunctions accessible by the main function when it is called.
I know that you can use whos within the function calling environment to return the variables stored in the function call stack. I would like to retrieve the sub-functions defined within the function file, and return them as a cell array of function handles.
Is this possible?
EDIT: the answer by #nirvana-msu has made my original request possible. However, now I find that it is more convenient to store these functions in a struct, so that I can refer to them by name:
For example:
fcn =
struct('sub_fn1', #sub_fn1, ...
'sub_fn2', #sub_fn2, ...
...
)
EDIT 2:
It is simply to convert the cell array obtained in the answer to a struct, simply use func2str:
fcns = cell2struct(fncs, cellfun(#func2str, fncs, 'uni', 0));
Use localfunctions - introduced in R2013b:
function main_fn()
fcns = localfunctions();
end
function sub_fn1()
end
function sub_fn2()
end
function sub_fnN()
end
It returns a cell array of function handles to all local functions in your file:
fcns =
#sub_fn1
#sub_fn2
#sub_fnN
I have a class with a scheduler function that is supposed to insert characters into a cell array:
classdef timeline < handle
properties
schedule
i
%other properties
end
methods
%other functions
function t = timeline()
%other initializations
t.schedule = cell(1,738);
t.i = 1;
end
function scheduler(t, g, fT)
if nargin == 2
fT = t.i;
end
if strcmp(g,'science')
'science' % eclipse occurs after
for j = (fT+t.sTime+1) : (fT+t.sTime+1+t.eTime)
t.schedule{j} = 'e';
end
elseif strcmp(g,'pass')
'pass' % science occurs 2 hrs after end
for j = (fT) : (fT+t.pTime)
t.schedule{j} = 'p'
end
for j = (fT+t.pTime+121) : (fT+t.pTime+120+t.sTime)
t.schedule{j} = 's';
end
scheduler(t, 'science', fT+t.pTime+120);
end
end
end
end
In the command window, I define my object t = timeline() and a mode g = 'pass' and then call the scheduler, t.scheduler(t,g).
It doesn't change the schedule property. What's going on inside the if statements to write the schedule isn't the problem I am concerned with. I put outputs in each part of the if statement, and found that strcmp is returning false and skipping over the whole block. So, I added a break point in the scheduler function, and found that for some reason g is passed to the function as another timeline object instead of the string 'pass'. Why is this?
When you call a method for an object you can use dot notation or function notation. Dot notation means you call the method using the dot operator on the object instance. For example,
obj.methodName(args);
In function notation you pass the object instance variable as the first argument to the method. For example,
methodName(obj, args);
Both the above calls are equivalent and call the same method in the object. In both the calls MATLAB passes obj as input to the method. Note the absence of obj as an argument in the dot notation. In dot notation obj, is added as an input argument before your args. In your code you are mixing both of these options. So you got two obj arguments for your method.
Relevant documentation is at http://www.mathworks.com/help/matlab/matlab_oop/method-invocation.html
We have this code in 'Reconstruction the subclass object from a saved struct' from MATLAB OOP documentation.
classdef MySuper
% Superclass definition
properties
X
Y
end
methods
function S = saveobj(obj)
% Save property values in struct
% Return struct for save function to write to MAT-file
S.PointX = obj.X;
S.PointY = obj.Y;
end
function obj = reload(obj,S)
% Method used to assign values from struct to properties
% Called by loadobj and subclass
obj.X = S.PointX;
obj.Y = S.PointY;
end
end
methods (Static)
function obj = loadobj(S)
% Constructs a MySuper object
% loadobj used when a superclass object is saved directly
% Calls reload to assign property values retrived from struct
% loadobj must be Static so it can be called without object
obj = MySuper;
obj = reload(obj,S);
end
end
end
I have a question about obj = MySuper. What is purpose of this line? How we can call MySuper object from this function without insert any object to loadobj function?
You first question is: What is the purpose of the obj = MySuper; line?
The answer is that the obj = MySuper; line initiates the variable obj as an element of the class MySuper. Non-static functions in a class will only run if the first input parameter is an instance of the class, so if obj is not initiated as a MySuper-object, then matlab will look for other functions called reload to run, and if none is found give you an error.
For your second question, I am not 100% sure what you mean. But I hope one of the following points will answer your question:
If you want to make a function that relates to a class, but not to a specific instance of the class, you can make a static function, these can take any input (also (if you want it that way) no input at all) - that is they don't need to have a first input parameter of the specific class.
To run a static function, use the class name followed by a dot and then the function name, so here you would type MySuper.loadobj(S) to run the function with the parameter S.
I would suggest that you try this out with the given example to better get to know the way oop works in matlab, you may for example try:
S.PointX = 1;
S.PointY = 2;
obj = MySuper.loadobj(S)
I hope this answers your questions.
I have to load some data in a structure.
I do it inside a function.
assuming that my structure is called
loaddata
and the data are in
loaddata.corrected_data
how can I access to it within a function?
function loaddata_struct(path,namestruct)
loaddata = load(path);
data = loaddata.corrected_data; % this should change depending on the argument of the function (namestruct in this case)
end
how can I pass the name of the structure? in this case corrected_data...
You can use dynamic field names like so:
fieldOfInterest = 'corrected_data';
data = loaddata.(fieldOfInterest);
If you're loading from file, you can also access the data directly
data = load('theDataFile.mat','-mat',fieldOfInterest)
The following code will return the structure's field with the name passed to loaddata_struct function:
function data = loaddata_struct(path,namestruct)
loaddata = load(path);
data = loaddata.(namestruct);
end
Use getfield and if you need to work on a 1 x N sized struct array -
function loaddata_struct(path,fname)
loaddata = load(path);
for k1 = 1:numel(loaddata)
data{k1} = getfield(loaddata(k1),fname);
end
return;
Thus, you can use it like this - loaddata_struct(path,'corrected_data')
Do it as text and use isfield and eval. Isfield will check if the string is a field of the struct, and if it is, then use eval to evaluate loaddata.fieldname. Using isfield you make sure you never get an error, and you can do things in the else, like finding the data that has the most similar name to the one inserted, for example.
function loaddata_struct(path,fieldname)
loaddata = load(path);
if isfield(loaddata ,fieldname)
data = eval(strcat('loaddata.',fieldname));
else
error('Heeey mate, thats not a field')
end
end