Loren on the Art of MATLAB

Use Dynamic Field References 28

Posted by Loren Shure,

Use dynamic field references, the notation .(), where possible, instead of setfield, getfield, and eval.

History

In MATLAB 6.5 (Release 13), we introduced dynamic field references into MATLAB. What are they and why should you use them?

In MATLAB, there are 3 basic types of arrays, traditional ones where you index using parentheses (), cell arrays where you can address the contents using curly braces {}, and structures (known in MATLAB as the type struct) where you access elements using the dot . notation.

Before R13, if you had collected information into a variable, call it ind, about which parts of an array you wanted to either index into or to change, you could do so using the variable in a straight-forward manner - if your array was a regular or cell array. By that, I mean that you could do things like:

y = x(ind)
x(ind) = 17
       
% With cells, you typically access the contents
% of one cell at a time.
c{ind(1)} = x(ind(1))

However, there was no symmetry with how to accomplish the same task if your array was a struct and you had the fieldnames in a variable; instead you had to use setfield and getfield. There was extra overhead for accessing structure elements compared to other array types. And that's why dynamic field indexing was introduced.

Example

Preferred:

fldnm = 'fred';
s.(fldnm) = 18;
y = s.(fldnm)

Not Recommended:

s  =  setfield(s,'fldnm',18);
y = getfield(s,'fldnm');

eval(['s.' fldnm ' = 18']);
eval(['y = s.',fldnm])

Benefits

  • Speed - when you can use .(), it is much faster. Part of the reason is because you don't have the overhead of calling yet another function, i.e., setfield or getfield. An additional reason is that MATLAB can work on the structure field in place and unnecessary copies are not made. Contrast these two cases, using setfield and using dynamic field referencing:
    s = setfield(s,fldnm,3);
    s.(fldnm) = 3;
    

    The first line requires at least 2 copies of the structure s while the second line requires space for only one instance.

  • Readability -- code is easier to understand since you can see the components of the structure.
  • Analyzability - programs that use eval can be particularly hard to analyze, for example for dependency reports.

Contraindications

  • There are certain very complex calling sequences for setfield that can't be translated into .() notation easily.
  • If you don't know the overall "structure" of your struct (e.g., all names at one "level"), it's hard to program generically with .()

28 CommentsOldest to Newest

I just stumbled across Loren’s blog quite by accident, and I really enjoy reading through the older postings. I think there is a solution to the second point in the Contraindications section of the article about dynamic field references: “If you don’t know the overall structure of your struct, … it’s hard to program generically with .()”

Use ‘fieldnames’ to retrieve the names of all fields at one level of the structure. I’ve done something similar to the following a number of times:

fn = fieldnames(mystruct);
for lp=1:length(fn)
doSomeOperation( mystruct.( fn{lp} ) );
end

I’ve become more comfortable just using the field names as the loop arguments outright.

fn = fieldnames(mystruct);
for lp=fn
doSomeOperation( mystruct( lp{:} ) );
end

This works very well for homogenous structures or when your ‘doSomeOperation’ function knows how to handle different input types.
For example, you might define doSomeOperation like this:

function x = doSomeOperation(y)
if ~isnumeric(y)
x = [];
else
x = doSomethingForReal(y);
end

Anyway, it’s a thought.

I am writing Matlab code using this notation in order to manage fields in Matlab. I think it is a very good method. I am wondering if codes written using this notation could lead some problems when Matlab Compiler is applied, as it happens for the “eval” function.
Eventually I ask you whether the use of “feval” can solve this problem or not.

Thank you very much.

Pietro Garofalo

Pietro-

There are no issues with using dynamic field referencing and the compiler. I don’t see how using feval helps in any way. This method should be robust.

–Loren

I happen to pass by your blog and saw your entries on MATLAB.
I would like to ask you regarding structure used in MATLAB.
But I am a beginner of MATLAB but I have to work on a project on B-splines.

>>>> My problem is that I currently can only plot one spline on the axes. My data will always be over-written the moment I plot another axes. However, when I read from the MATLAB book. It seems that the example are assigning data to structure in a less interactive way with the user. Is there any ways that I can work on the data clicked by the user. Then retrieving the relevant data upon selecting on the spline drawn.

Another problem of mine is that, after I have shifted the original spline to another location. After I apply ‘cla’ function, all the splines have been deleted. Is there any other functions that I can used to delete the original spline after shifting the spline to a new location without deleting other splines on the axes.

Thanks a million,
Magdalene

I’m using some super dumb techniques to process multiple variables with a differing prefix..

var_str = {‘gamrf’,’pt’,’s’};
for var = 1:length(var_str)
string = strcat(var_str{var},’mean_max = squeeze(max(shiftdim(‘,var_str{var},’mean,2)));’); cmd = char(string); eval(cmd);
string = strcat(var_str{var},’mean_min = squeeze(min(shiftdim(‘,var_str{var},’mean,2)));’); cmd = char(string); eval(cmd);
end

This is really hitting things with a hammer.. Can someone direct me to an enlightening way of digging myself out of hammerland?

Paul-

Follow the ideas in this blog article instead! Do NOT name your variables specially. Instead use some base name for a structure and have the fields be the various names you want to refer to. That is one of the main points of the article.

–Loren

Hi Loren,

I stumbled upon this page while searching a solution to following problem. I searched usergroups to no avail.

I need to retrieve value of a field from the structure and name of the field is based on user input. Following is the sample code:

test.fourarray=zeros(3,3,3,3);
fname=’fourarray';

eval([‘test.’ ‘fourarray’]);
ERROR: ??? Index exceeds matrix dimensions.

I just can’t figure out what’s happening!
Why do I get above error (which occurs btw irrespective of the size and type of the field)?

Shalin-

Something else must be going on (or there’s a bug in the version you are running). I just tried your code in R2008b and it works fine.

However, you don’t need the eval statement. Try this instead:

test.(fname)

and add whatever trailing indexing you want.

–Loren

Yes something else was wrong (may be spurious variables in workspace). It worked alright after clearing unused workspace variables.

Thanks…

Hi Loren,

regarding number 6. I have a similar problem.

I have perform an simulation with Simulink and have stored some variables with Simulink ToWorkspace blocks at my workspace. Due to this I have now variables with a special name at my workspace e.g.

a = 3;
b = 4;
c = 5;

Now I want to save the simulation results at a data structure (e.g. D). At a cell array (e.g. simResults), I have stored all names of the variables which will be stored by the ToWorkspace blocks at the workspace:

simResults = {‘a';’b';’c’};

When I try to save the simulation results at my data structure D, I can’t solve it without eval(). Can you please help me, to do it without?

D = struct();

for i = 1:length(simResults)
% Desired, something without eval()
% D.(simResults{i}) = .(simResults{i});
% Possible, at the moment only with eval()
D.(simResults{i}) = eval(simResults{i});
end

-Frank

Frank-

You can’t do that without eval. There is not way to reference a variable without naming it unless you somehow create an appropriate string to evaluate.

You are better off creating the structure and using that to start with, if that’s an option. Or use a cell array, one cell per variable, similarly.

–Loren

Hi Loren,

Are dynamic fields the same thing people call in Perl or Python hatches (previously known as associative arrays)? I am in the bioinformatic area and most scientists use Python or Perl and usually pick on me ’cause Matlab doesn’t have hatches. I found dynamic fields some time ago but still have doubts whether they are the same thing.

Thanks,
A

Alex-

Sort of but not really (and I think you mean hash perhaps, not hatch?)… structs are more like structures in C. the containers.Map class is more like associative arrays in perl or python. The notation .() simply allows variable “indexing” into a struct with a variable fieldname rather than just a fixed literal string.

–Loren

Hi Loren,
In my application, I am creating a very large map of key-value pairs. I’m currently using a structure with dynamic field names, and adding key-value pairs on-the-fly is a bottleneck. I would like to preallocate to speed it up, and I can’t find any reference to doing this. How would one go about preallocating a structure with dynamic field names?
I could also use a map container for this purpose, so if it isn’t possible with dynamic field names, how does one preallocate a container map?
Thanks,
Joanne

Joanne-

I am not sure what you are trying to accomplish, but if you know the names in advance, you can preallocate them something like this.

fn = {'ref' 'doc' 'tam'};
for ind = 1:length(fn)
   a.(fn{ind}) = [];
end

I am not sure that’s going to make much difference though. The contents of each field in a struct has to have contiguous memory, but the various struct fields don’t have that restriction.

And of course, there is “substruct” to handle multiple field names but requires a bit of work to define the right input …

Awesome explanation. I attempted eval() for a few days until finding about dynamic field references.

Is there a generalized way to access deeper into a structure? For example,

A.l1.l2.l3.l4 = 1234

%would like to do this:
fieldname = 'l1.l2.l3.l4'    %next time might be 'l1.l2' 
A.(fieldname)
%gives:  ??? Reference to non-existent field 'l1.l2.l3.l4'.

A.('l1').('l2').('l3').('l4')
%gives correct: 1234

Loren,

Let me rephrase. If I have a structure of arbitrary depth:

A.L1.L2.L3...LN = value;
fullString = 'L1.L2.L3...LN';

is there a way to elegantly access a field given by fullString? It would be simple enough if the depth if fixed, but the only generalized way I can think is to parse the string and iteratively store substructures until the final result is obtained:

A.L1.L2.L3.L4.L5 = 12345;
fullString = 'L1.L2.L3.L4.L5';

dotFind = strfind(fullString,'.');
temp = A;
while ~isempty(dotFind)
  temp = temp.(fullString(1:dotFind(1)-1));
  fullString = fullString(dotFind(1)+1:end);
  dotFind = strfind(fullString,'.');
end
FinalAns = temp.(fullString);
disp(FinalAns);

While this works, it is not very elegant, efficient, or readable. fullString will change in the program. One time it may be ‘L1.L2.L3′. The next it might be ‘L1.M2.N3.L4′. Being somewhat new to dynamic field names (thank you, Loren for many other postings elsewhere), I had hoped/expected to just be able to use: A.(fullString) which obviously does not work.

Eric-

I understand the problem you are trying to solve but don’t have any way besides getting the individual fieldnames. You might put in an enhancement request to get functionality like you describe. The link for support is on the right side of my blog.

–Loren

Eric-

You can do what Cris says, but using eval is highly NOT recommended in general.

–Loren

I’m using dynamic field reference to organize input data into a structure.

here’s a simple example:
B =

[1] ‘M1′ ‘test’
[1] ‘M2′ [ 2]
[AA ~] = size(B);
for xx = 1:1:AA
data.(B{xx,2}).time = B{xx,1};
data.(B{xx,2}).num = B{xx,3};
end

Is there a way to do this without resorting to a look through all the rows of B? Something closer to:
data.(B{:,2}).time = B{:,1};
data.(B{:,2}).num = B{:,3};

Thanks.

Chris-

You can’t reference a structure that way with multiple field names in one particular position, with or without dynamic field reference. It always requires a scalar field name.

–Loren

Eric,

Your proposed while-loop reminded me of some of my own code, which might possibly be slightly more readable, due to leveraging regexp(), so I thought I’d post..

I wrote a class ‘FieldInterface’ to encapsulate arbitrary-depth struct fields, just as you’re talking about, so I can do things like:

————————————–

A.setField(‘A.B.C.D’,20);
ans = A.getField(‘A.B.C.D’);

————————————–

The code snip below is the essence of method getField(). Note the reference to classdef constant ROOT_FIELD_NAME, which anchors the “dynamic” Fields.

————————————–

function outValue = getField(obj,varargin)

fieldSpecStr = varargin{1};

try

% Construct near-complete field name (only lacking ‘obj.’), e.g.
% ‘ROOT_FIELD_NAME.subStructName.fieldName’
fullFieldStr = [ obj.ROOT_FIELD_NAME ‘.’ fieldSpecStr ];

% Get cell vector of sub-struct / field names within (fullFieldStr)
cvFieldSplits = regexp(fullFieldStr,’\.’,’split’);

% Initialize (outValue):
outValue = obj;

% Iterate through (cvFieldSplits)
for iSplit = 1 : numel(cvFieldSplits)

% Access next-level within (cvFieldSplits), which will either be a
% further sub-struct or else the final, desired field:
outValue = outValue.(cvFieldSplits{iSplit});
end

% Handle failure
catch exception

end

————————————–

Hope s/o finds this useful. Any comments appreciated,

Brad

p.s. Loren/Webmaster: I couldn’t get the “pre” tags to work for me, to set off code blocks. Maybe please compare implementation here vs. MATLAB Answers, which uses a slightly different syntax for code blocks, I think.. Also, it would be really convenient if this blog could offer a checkbox to email readers/posters when new comments are added, as does MATLAB Answers & many other forums on the Net..

These postings are the author's and don't necessarily represent the opinions of MathWorks.