Loren on the Art of MATLAB

Turn ideas into MATLAB

What’s the Big deal? 15

Posted by Loren Shure,

So, what is the big deal? To start with, this week marks my 19th anniversary at MathWorks. Never would I have guessed back then what I am up to now, including talking about MATLAB with so many customers. I look forward to many more years working with MATLAB at MathWorks and meeting and working with so many wonderful customers.

In a recent post on the MATLAB newsgroup, Duane Hanselman mentioned that he found something interesting in the help for deal, namely the note:

In many instances, you can access the data in cell arrays and structure fields without using the deal function.
and he went on to ask when this was introduced. To find the answer, I did some archaeology in the MATLAB Release Notes and found some information in the notes for Release 14, MATLAB 7.

Why did we introduce this? Here are some of our thoughts from our design discussions:

  • Users either have to use deal or a loop to extract information from a cell array or a field of a struct array.
  • c{:} and a(:).fn both produce comma-separated lists in MATLAB. Before this change, you could enclose these expressions in square brackets ([ ]), curly braces ({ }), or parentheses for a function call (foo( )). Otherwise, they produced as many outputs as the length of the array input, each successively assigned to ans.
  • Because we were now allowing assignment with a comma separated list on the right hand side where it was not possible before, we were not going to break working code.
  • The idea seemed both natural and welcome when we spoke to some M programmers at MathWorks.

The biggest problem I see with this new construct is that it seems to have taken a while to get the exposure it deserves. While there is still clearly a role for deal, it's required less often than before MATLAB 7.

One code pattern I have seen deal used for is renaming variables. For example, you can swap the values of A and B with this:

    [B,A] = deal(A,B);

With the use of anonymous functions you can also accomplish the same outcome:

   swap=@(varargin)varargin{nargin:-1:1};

Now let's see what that does:

   a = 1;
   b = 2;
   c = 17;
   [a,b,c] = swap(a,b,c)

and the output looks like this:


a =

    17


b =

     2


c =

     1

There will be more in future articles on function handles, anonymous functions and nested functions. I have received suggestions for article topics from several of you and would love to gather even more input. Please keep the feedback coming!

Note

Comments are closed.

15 CommentsOldest to Newest

Keld replied on : 1 of 15
Hello Loren, I've trying to convert my structure fields into variables, but it seems nobody is interested in this. My line of thought goes like this: s.a = 1:3 s.b = 3x8 double s.c = 25x2 char array then struct2vars(s) produces a = 1:3 b = 3x8 double c = 25x2 char array how can I achieve this? Keld
Loren replied on : 2 of 15
Hi Keld- You can't do this easily in MATLAB. You could get the fieldnames of s and then use eval to create the variables, but using eval makes your program much harder to analyze and makes it less robust. Suppose later in your program, you want to call the function var. That's all well and good, unless you now introduce a variable named var. Later, when you hit the statement where you intend the function to be called, you may or may not get a result, and it's likely not what you wanted or were expecting.

Far better to use the fields of the struct or put the variables into a cell array... --Loren

Ron replied on : 3 of 15
Hello, I was searching for a way to do exactly what Keld was asking. I was trying to do something like: a.b = 1; a.c = 2; a.d = 3; cellArray = struct2cell(a); names = fieldnames(a); eval([ '[',[names{:}],'] = deal(cellArray{:})']) which doesn't work because the eval string = [bcd] = deal(cellArray{:}) when it needs to be: [b, c, d] = deal(cellArray{:}) Is there a clever way to fix this without a for loop? Thanks! Ron Elmer
Loren replied on : 4 of 15
Ron- As many have noted, dynamically creating variable names in MATLAB is not a good practice. MATLAB does not always take kindly to variables being placed into the workspace, via eval and cousins, behind its back, so=to-speak. --Loren
Oktay replied on : 5 of 15
Hello, I don't know if it's really related to "deal" but I am just going to ask. Suppose that we have a function as follows: function [a b] = f(varargin) a = 1; b = 2; and somewhere we need B. So we type: [temp b] = f(); which gives us a useless variable TEMP together with an M-lint warning. Moreover, if we want to call another function with input B, we need to do this in an another statement. (If it weren't a function, we could use SUBSREF) So, is there a way to to achieve this in one statement? And is there a way not to introduce the TEMP variable? Thank you for your interest. And by the way keep up the great work. I gained so much from your columns. Oktay
Loren replied on : 6 of 15
Oktay- Depending what version of MATLAB you use, you shouldn't see the mlint warning (the later the version, the better for that). There is no way to ask for just the 2nd output, so you can't do what you want in a single statement unless you make your own function to index into outputs and grab the one you want with an extra function wrapped around the function f you are calling. We have it as an enhancement in our feature database to allow skipping assignment to earlier output variables. Today some people suggest doing something like this.
[B,B] = f(...)
so B gets overwritten. I don't care for that as it assumes behavior of MATLAB (left-to-right) that we never wrote down and documented so could conceivably change it should that allow something new to be possible where it wouldn't otherwise. --Loren
Hoi Wong replied on : 7 of 15
Hi Loren, regarding Oktay's proble, would you consider in future versions of MATLAB, create a 'dummy' or 'unwanted' class or keyword for people to dump unwanted output arguments into a black hole, and have MATLAB warn you when you are trying to reuse it? This will avoid a lot of sloppy code changes when a program is maintained by multiple people.
Loren replied on : 8 of 15
Hoi- Thanks for code for Kled. We have the enhancement requested logged to create a way to dump unwanted outputs. Nothing like this is yet in a shipping MATLAB, including R2009a which is now out. --Loren
Hoi Wong replied on : 9 of 15
Regarding Kled's comment, here's the function to achieve this: function varargout=struct2vars(S) C = struct2cell(S); varargout = {C{:}}; end However, the output follows the ordering of your struct.
Hoi Wong replied on : 10 of 15
Hi Loren, after another user suggested using C = struct2cell(S) ; [a,b,c] = deal(C{:}) to replace struct2vars(), I have another question for you: is there any reason why MATLAB doesn't allow something this? [a, b, c]=(struct2cell(S)){:} In other words, if it makes sense to say C=magic(2)+rand(2) [plus() operator], why can't I say (magic(2))(:,2) or (magic(2)){:,2} [subsref() operator]?
Loren replied on : 11 of 15
Hoi Wong- At the moment, MATLAB doesn't allow indexing into temporary variables. They must be assigned first. We have the enhancement suggestion on the books, but I have no timeline for introducing the feature. --Loren
Hoi Wong replied on : 12 of 15
I haven't thought I'd end up using struct2vars() myself, but it just happened today when I'm trying to cache all the needed variables in a struct inside appdata(0) and release them back into workspace. Because I want variable transparency in my code, I'm reluctant to use assigin, and here's a complete usage of struct2vars: variableNames = fieldnames(S); [variableNames{:}]=struct2vars(S); With that, I don't even have to keep track of the order of the variable names.
Oliver Woodford replied on : 13 of 15
Sometimes I use deal to initialize the cells of a cell array. E.g. A = cell(2,3); [A{:}] = deal(zeros(3));
Hoi Wong replied on : 14 of 15
Hi Oliver, Very slick idea, and I was tempted to use it myself for large data set, but I have to do a performance test first: >> tic, A=cell(140); [A{:}]=deal(zeros(140)); toc Elapsed time is 0.936412 seconds. >> tic, B=cell(140); B=num2cell(zeros(140)); toc Elapsed time is 0.008790 seconds. Loren: can you comment on the performance of unpacking cells into comma separated lists? It's a handy tool, but I'm a little concerned that overusing it can lead to slow performance.
Oliver Woodford replied on : 15 of 15
Hoi Wong: Note that the A and B that you generate are different. The deal method initializes every cell in A with zeros(140). To do this using the num2cell method you should do: >> tic, B=squeeze(num2cell(zeros(140,140,140,140),1:2)); toc ??? Error using ==> zeros Out of memory. Type HELP MEMORY for your options. However, to replicate what you did using num2cell (initializing every cell to 0) using deal, I would do: >> tic, A=cell(140); [A{:}]=deal(0); toc Elapsed time is 1.740839 seconds. >> tic, B=num2cell(zeros(140)); toc Elapsed time is 0.012501 seconds. So your query about turning cells into comma separated lists is still valid. Oliver