Thread Subject: genvarname doesn't work

Subject: genvarname doesn't work

From: Juliette Salexa

Date: 10 Jul, 2009 17:20:18

Message: 1 of 15

I have R2007b, and copied and pasted this code from the matlab documentation:

for k = 1:5
   t = clock;
   pause(uint8(rand * 10));
   v = genvarname('time_elapsed', who);
   eval([v ' = etime(clock,t)'])
   end

and it doesn't work because genvarname('aa') gives [0 0]
ie, for every character in the string, a new element is created in the output vector.

The code above doesn't even run without an error message. Was this function modified in a new version of matlab or something ??

Subject: genvarname doesn't work

From: Wayne King

Date: 10 Jul, 2009 17:38:02

Message: 2 of 15

Hi Juliette, The included code runs fine for me on R2007b (Windows) and I see nothing in the bug reports. Can you give us the error message?

wayne

"Juliette Salexa" <juliette.physicist@gmail.com> wrote in message <h37t8i$6kh$1@fred.mathworks.com>...
> I have R2007b, and copied and pasted this code from the matlab documentation:
>
> for k = 1:5
> t = clock;
> pause(uint8(rand * 10));
> v = genvarname('time_elapsed', who);
> eval([v ' = etime(clock,t)'])
> end
>
> and it doesn't work because genvarname('aa') gives [0 0]
> ie, for every character in the string, a new element is created in the output vector.
>
> The code above doesn't even run without an error message. Was this function modified in a new version of matlab or something ??

Subject: genvarname doesn't work

From: Juliette Salexa

Date: 10 Jul, 2009 17:51:03

Message: 3 of 15

Thank Wayne,
I did clear('all') then reran the code and it worked, so it must have been some predefined variable in my workspace messing it up.

Anyway, I can't seem to get this to work.

If I have an array of strings like:

xhat=['a' 'b' 'c' 'd'];

and I want to define 4 variables whose names are the elements of xhat.. let's say for example, I wanted a=1,b=2,c=3,d=4 ... it would be nice if I could do:

for i=1:4
 genvarname(xhat(i))=i
end

But this does not work as I discovered in the documentation for genvarname:
"genvarname returns a string that can be used as a variable name. It does not create a variable in the MATLAB workspace. You cannot, therefore, assign a value to the output of genvarname."

is there a way ??

Subject: genvarname doesn't work

From: Ashish Uthama

Date: 10 Jul, 2009 18:11:13

Message: 4 of 15

On Fri, 10 Jul 2009 13:51:03 -0400, Juliette Salexa
<juliette.physicist@gmail.com> wrote:

> Thank Wayne,
> I did clear('all') then reran the code and it worked, so it must have
> been some predefined variable in my workspace messing it up.
>
> Anyway, I can't seem to get this to work.
>
> If I have an array of strings like:
>
> xhat=['a' 'b' 'c' 'd'];
>
> and I want to define 4 variables whose names are the elements of xhat..
> let's say for example, I wanted a=1,b=2,c=3,d=4 ... it would be nice if
> I could do:
>
> for i=1:4
> genvarname(xhat(i))=i
> end
>
> But this does not work as I discovered in the documentation for
> genvarname:
> "genvarname returns a string that can be used as a variable name. It
> does not create a variable in the MATLAB workspace. You cannot,
> therefore, assign a value to the output of genvarname."
>
> is there a way ??


 From the help:

     Examples:

         genvarname({'file','file'}) % returns {'file','file1'}
         a.(genvarname(' field#')) = 1 % returns a.field0x23 = 1

Using dynamic structure fields is probably the best approach if you want
to do something like this.

Subject: genvarname doesn't work

From: Juliette Salexa

Date: 10 Jul, 2009 20:53:01

Message: 5 of 15

So I'm guessing there's no way to do this in matlab ??

Subject: genvarname doesn't work

From: Steven Lord

Date: 10 Jul, 2009 21:02:01

Message: 6 of 15


"Juliette Salexa" <juliette.physicist@gmail.com> wrote in message
news:h389nd$omc$1@fred.mathworks.com...
> So I'm guessing there's no way to do this in matlab ??

You CAN create variables dynamically from strings containing their names in
MATLAB using EVAL.

However, you SHOULD NOT create variables dynamically from strings containing
their names in MATLAB using EVAL

See question 4.6 in the newsgroup FAQ for an explanation of why you should
not do this.

http://matlabwiki.mathworks.com/MATLAB_FAQ

Your code is going to be harder to read if you "poof" variables into
existence at runtime like this, and if you introduce a bug into your code
that uses this approach it may be very difficult to debug and fix.

--
Steve Lord
slord@mathworks.com

Subject: genvarname doesn't work

From: Oleg Komarov

Date: 10 Jul, 2009 21:34:02

Message: 7 of 15

"Steven Lord" <slord@mathworks.com> wrote in message <h38a6i$pud$1@fred.mathworks.com>...
>
> "Juliette Salexa" <juliette.physicist@gmail.com> wrote in message
> news:h389nd$omc$1@fred.mathworks.com...
> > So I'm guessing there's no way to do this in matlab ??
>
> You CAN create variables dynamically from strings containing their names in
> MATLAB using EVAL.
>
> However, you SHOULD NOT create variables dynamically from strings containing
> their names in MATLAB using EVAL
>
> See question 4.6 in the newsgroup FAQ for an explanation of why you should
> not do this.
>
> http://matlabwiki.mathworks.com/MATLAB_FAQ
>
> Your code is going to be harder to read if you "poof" variables into
> existence at runtime like this, and if you introduce a bug into your code
> that uses this approach it may be very difficult to debug and fix.
>
> --
> Steve Lord
> slord@mathworks.com
>
What Lord is talkin about is:
List = {'A','B','C'};
for i = 1 : length(List)
      eval([List{i} ' = i;' ]);
end
1. Really hard to read
to understand --> execute just "[ List{i} ' = i ;']" (for i =1) --> "A = i;"
the eval evaluates the command writtens as a string.
2. The M_lint "can't" read inside the eval([...]), or more properly said, it doesnt recognize what in the .m file is written as a string will become a variable!

Subject: genvarname doesn't work

From: Oleg Komarov

Date: 10 Jul, 2009 21:35:02

Message: 8 of 15

"Steven Lord" <slord@mathworks.com> wrote in message <h38a6i$pud$1@fred.mathworks.com>...
>
> "Juliette Salexa" <juliette.physicist@gmail.com> wrote in message
> news:h389nd$omc$1@fred.mathworks.com...
> > So I'm guessing there's no way to do this in matlab ??
>
> You CAN create variables dynamically from strings containing their names in
> MATLAB using EVAL.
>
> However, you SHOULD NOT create variables dynamically from strings containing
> their names in MATLAB using EVAL
>
> See question 4.6 in the newsgroup FAQ for an explanation of why you should
> not do this.
>
> http://matlabwiki.mathworks.com/MATLAB_FAQ
>
> Your code is going to be harder to read if you "poof" variables into
> existence at runtime like this, and if you introduce a bug into your code
> that uses this approach it may be very difficult to debug and fix.
>
> --
> Steve Lord
> slord@mathworks.com
>
What Lord is talkin about is:
List = {'A','B','C'};
for i = 1 : length(List)
      eval([List{i} ' = i;' ]);
end
1. Really hard to read
to understand --> execute just "[ List{i} ' = i ;']" (for i =1) --> "A = i;"
the eval evaluates the command writtens as a string.
2. The M_lint "can't" read inside the eval([...]), or more properly said, it doesnt recognize what in the .m file is written as a string will become a variable!

Subject: genvarname doesn't work

From: Juliette Salexa

Date: 10 Jul, 2009 22:02:03

Message: 9 of 15

I read the FAQ page, thank you Steven and Oleg.
It seems that Matlab is very adament about us not poofing variable names at runtime.

Is this only because it's harder to read, and therefore harder to debug ??

Because they could change the syntax so that it's not so hard to read:

x=['a' 'b' 'c' 'd'];
for i=1:4
 Mygenvarname(x(i))=i
end

The reason why is that, for a very hypothetical example, say the letter n represents the number of occurrences of 'n' in an article.

If I want to report that number from an array, I would have to figure out that n is the 14th letter of the alphabet, and type the command array(14) to get my result. What if I don't know off the top of my head that n is 14th in the alphabet ?? I would rather be able to just type "n" and get my answer.

Matlab's solution to this on the FAQ page is to use a structure s.a, a.b, s.c .... s.n ....

I'm not too familiar with structures .. but it seems as if they take up more memory and are a more complex data structure in general .. it seems like its harder to access or view information contained in them.. I'm probably wrong, but can someone please explain to me why ??

Subject: genvarname doesn't work

From: dpb

Date: 10 Jul, 2009 22:52:10

Message: 10 of 15

Juliette Salexa wrote:
> I read the FAQ page, thank you Steven and Oleg. It seems that Matlab
> is very adament about us not poofing variable names at runtime.

In this case "TMW" instead of "ML" but, yes... :)

> Is this only because it's harder to read, and therefore harder to
> debug ??

That's one of the given reasons.

> Because they could change the syntax so that it's not so hard to
> read:
>
> x=['a' 'b' 'c' 'd']; for i=1:4 Mygenvarname(x(i))=i end

But reread the examples on potential problems w/ variable naming, etc.

But don't undersell the importance of clarity in written code and the
use of some slight additional complexity (perhaps) in the
implementation. Unless the code is simply a "throw away" one-use hack,
it's quite possible it may be needed to be maintained and developed for
quite some time and also by somebody else. This effort often in real
life will dwarf the initial effort and anything that can do up front to
help in that process later on is well worthwhile. Also, even if it us
"just your code", a few months from now when it's no longer so familiar,
you'll thank yourself you didn't obuscate...(damhikt :) ).


..snip another explanation/justification...

> Matlab's solution to this on the FAQ page is to use a structure s.a,
> a.b, s.c .... s.n ....
>
> I'm not too familiar with structures .. but it seems as if they take
> up more memory and are a more complex data structure in general .. it
> seems like its harder to access or view information contained in
> them.. I'm probably wrong, but can someone please explain to me why
> ??

Again from the FAQ...

"MATLAB arrays (either numeric or cell) will let you do the same thing
in a much faster, much more readable way."

"...use structures instead of cell arrays. The fields of the structure
can be the variable names you want. And you can index into them with
dynamic field references."

I would suggest re-reading that subsection and looking at the sample
code. The level of indirection is minor and the benefit is major. Is
it really _THAT_ much more effort to type x.name that you'll go to the
trouble to poof the name "name" w/ the possible syntax issues outlined?

And, lastly, go back to the first sentence in the FAQ quoted above--it's
simply better-performing. It avoids the high overhead operation of
EVAL(), _a_good_thing (tm) in its own right...

Time and experience will breed familiarity and you'll soon be glad you
escaped the trap despite some initial growing pains...

--

Subject: genvarname doesn't work

From: Steven Lord

Date: 13 Jul, 2009 02:11:42

Message: 11 of 15


"Juliette Salexa" <juliette.physicist@gmail.com> wrote in message
news:h38dor$hld$1@fred.mathworks.com...
>I read the FAQ page, thank you Steven and Oleg.
> It seems that Matlab is very adament about us not poofing variable names
> at runtime.
>
> Is this only because it's harder to read, and therefore harder to debug ??
>
> Because they could change the syntax so that it's not so hard to read:
>
> x=['a' 'b' 'c' 'd'];
> for i=1:4
> Mygenvarname(x(i))=i
> end

Write this function:

function y = mysin(x)
eval('sin = 5');
y = sin(x)

and call it with:

y = mysin(1)

What do you expect this function call to return, and what does it actually
return?

You may expect it to return the first element of the variable you created
inside EVAL, 5. It doesn't -- it returns the sine of 1 radian, because
MATLAB parsed the M-file, found no indication it could see that sin was a
variable, and so decided that the reference to sin on the third line was
actually a call to the SIN function.

Now in a situation like this, with a three-line M-file, that problem is
(relatively) easy to diagnose. What if this was a three hundred-line
function, and the EVAL call and the use of the "poofed" variable were
separated by 100 lines of code?

In addition to bugs, if you create variables at runtime without any
indication when the M-file is parsed that they will be variables, MATLAB may
not be able to optimize it as effectively as it would if it knew at
parse-time what was a variable and what wasn't.

> The reason why is that, for a very hypothetical example, say the letter n
> represents the number of occurrences of 'n' in an article.
>
> If I want to report that number from an array, I would have to figure out
> that n is the 14th letter of the alphabet, and type the command array(14)
> to get my result. What if I don't know off the top of my head that n is
> 14th in the alphabet ?? I would rather be able to just type "n" and get my
> answer.

convertLetterToIndex = @(x) x-'a'+1;
array(convertLetterToIndex('n'))

or

N = 14;
array(N)

or, if array is a struct array:

array.('n')

> Matlab's solution to this on the FAQ page is to use a structure s.a, a.b,
> s.c .... s.n ....
>
> I'm not too familiar with structures .. but it seems as if they take up
> more memory and are a more complex data structure in general .. it seems
> like its harder to access or view information contained in them.. I'm
> probably wrong, but can someone please explain to me why ??

Struct arrays do have some overhead above what is required for a regular
array, and using them in code is somewhat different than using regular
numeric arrays. Yet if I had the choice to use struct arrays or EVAL in a
piece of code to work with some sort of "dynamically created variables", I'd
prefer structs over EVAL most of the time.

--
Steve Lord
slord@mathworks.com

Subject: genvarname doesn't work

From: Juliette Salexa

Date: 23 Jul, 2009 22:55:02

Message: 12 of 15

Okay Steven Lord, you have definitely convinced me that there are advantages of not poofing variables into existence, but how could a loop like this be done without poofing variables ??
---------------------------------------------------
A='AB';
z=1;
for a=1:length(A) for b=1:length(A) for c=1:length(A) % for d=... for e=...
            A3(z,1)=A(a);
            A3(z,2)=A(b);
            A3(z,3)=A(c);
% ................. do the same for d, e , up to , let's say n
            z=z+1; end
            end
        end
---------------------------------------------------

It would take too long to type out "for" and "end" n times.
The only way I see this being done is something like:

indices={'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o'};
for y=1:length(indices)
    for indices{y}=1:length(A)
            string(z,y)=A(indices(y));
...

But at line 3 we are poofing a new variable at each iteration of the for loop. The first time we are poofing a, the second time b, etc...


Is there a way to do this without poofing variables ??
------------------------------------------------------------------------------------------------------
Also, the using eval command doesn't necessarily mean we're poofing variables into existence.... Let's say we had the variables AAAA,AAAB,AAAC,......DDDC,DDDD ALREADY defined and set to equal numerical values. Now I want to put only ones with two of the same letter into a cell array.

So I should get a cell array like:
cell= {AABB,AACC,AADD,BBAA,BBCC....DDCC}

WITH their numerical values attached to those cell array entries. Defining the cell the way I did just now would take a long time especially if we add E and F. But one thing I can do is come up with an algorithm that generates the names of the variables I want, and then defines those variables to equal the corresponding variables that previously existed, using the eval command and "poofing" variables (already they already existed before).

Would there be a way out of this one ?? Does it involve the symbolic toolkit ??

Subject: genvarname doesn't work

From: Steven Lord

Date: 24 Jul, 2009 15:00:32

Message: 13 of 15


"Juliette Salexa" <juliette.physicist@gmail.com> wrote in message
news:h4apo6$143$1@fred.mathworks.com...
> Okay Steven Lord, you have definitely convinced me that there are
> advantages of not poofing variables into existence, but how could a loop
> like this be done without poofing variables ??
> ---------------------------------------------------
> A='AB';
> z=1;
> for a=1:length(A) for b=1:length(A) for c=1:length(A) % for d=... for
> e=...
> A3(z,1)=A(a);
> A3(z,2)=A(b);
> A3(z,3)=A(c);
> % ................. do the same for d, e , up to , let's say n
> z=z+1; end
> end
> end
> ---------------------------------------------------
>
> It would take too long to type out "for" and "end" n times.
> The only way I see this being done is something like:
>
> indices={'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o'};
> for y=1:length(indices)
> for indices{y}=1:length(A)

This won't work.

> string(z,y)=A(indices(y));
> ...
>
> But at line 3 we are poofing a new variable at each iteration of the for
> loop. The first time we are poofing a, the second time b, etc...
>
>
> Is there a way to do this without poofing variables ??

Yes.

A = 'AB';
nvariables = 5;
clear c
[c{1:nvariables}] = ndgrid(A);
A3 = repmat(' ', numel(c{1}), nvariables);
for k = 1:nvariables
    A3(:, k) = c{k}(:);
end

Or, if you don't like comma-separated lists and don't mind the combinations
being in a little different order:

A = 'ABC';
nvariables = 5;
len = numel(A);
numCombs = len^nvariables;
ind = dec2base(0:(numCombs-1), len);
A(ind-'0'+1)

> ------------------------------------------------------------------------------------------------------
> Also, the using eval command doesn't necessarily mean we're poofing
> variables into existence.... Let's say we had the variables
> AAAA,AAAB,AAAC,......DDDC,DDDD ALREADY defined and set to equal numerical
> values. Now I want to put only ones with two of the same letter into a
> cell array.
>
> So I should get a cell array like:
> cell= {AABB,AACC,AADD,BBAA,BBCC....DDCC}
>
> WITH their numerical values attached to those cell array entries.
> Defining the cell the way I did just now would take a long time especially
> if we add E and F. But one thing I can do is come up with an algorithm
> that generates the names of the variables I want, and then defines those
> variables to equal the corresponding variables that previously existed,
> using the eval command and "poofing" variables (already they already
> existed before).
>
> Would there be a way out of this one ?? Does it involve the symbolic
> toolkit ??

The first alternative I can think of would involve a slight modification to
the problem statement -- rather than creating all those variables
individually, I would have created them as fields of a struct array. If you
did that, you could use the FIELDNAMES function to determine what fields the
struct array had, figure out which fields match your condition, and use
those with dynamic field names to extract the appropriate fields from the
struct.

I know what I'm about to say may sound shocking, but there are some uses
where EVAL (or more frequently its cousins EVALC and EVALIN) is useful
and/or necessary. In those use cases, ASSUMING you know the consequences of
EVAL and you ACCEPT those consequences, go ahead and use EVAL/EVALC/EVALIN.
What I want you, and others, to avoid is using EVAL _where it's not needed_
or _where there are more robust alternatives that don't have the same
consequences._ EVAL is a sledgehammer -- sometimes you need a sledge to do
your work, but you probably shouldn't use it to drive the nail from which
you're going to hang a picture into the wall or the screw you're using to
assemble your new desk.

--
Steve Lord
slord@mathworks.com

Subject: genvarname doesn't work

From: Juliette Salexa

Date: 27 Dec, 2009 20:27:03

Message: 14 of 15

"Steven Lord" <slord@mathworks.com> wrote in message > Yes.
>
> A = 'AB';
> nvariables = 5;
> clear c
> [c{1:nvariables}] = ndgrid(A);
> A3 = repmat(' ', numel(c{1}), nvariables);
> for k = 1:nvariables
> A3(:, k) = c{k}(:);
> end
>
> Or, if you don't like comma-separated lists and don't mind the combinations
> being in a little different order:
>
> A = 'ABC';
> nvariables = 5;
> len = numel(A);
> numCombs = len^nvariables;
> ind = dec2base(0:(numCombs-1), len);
> A(ind-'0'+1)
----------------------------------------------------------

Steve Lord you are a genius!

This was very helpful, although it's probably going to take me a long time to decipher what you're doing.

Only an expert like you could come up with something that clever!

Subject: genvarname doesn't work

From: Juliette Salexa

Date: 27 Dec, 2009 21:17:05

Message: 15 of 15

"Juliette Salexa" <juliette.physicist@gmail.com> wrote in message > Steve Lord you are a genius!
>
> This was very helpful, although it's probably going to take me a long time to decipher what you're doing.
>
> Only an expert like you could come up with something that clever!
-------------------
Actually wait, I just realized,
after finally figuring out what these codes do, that these are just more clever ways of solving my problem, that avoid doing the loops over many variables.

As I said before, this problem of generating all permutations with repetition was already solved by Matt Fig's npermutek.m [ a=npermutek(1:k,n) does the trick ]

What I really wanted to know was if there was a way to loop over an array of variables like:
-------------------
for a=1:5; for b=1:5; for c=1:5; % for d=... for e=...
answer=a+b+c+ ... ;
end end end end ...
-------------------

But without typing all of those for's and end's. So something like:
-------------------
indices={'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o'};
for y=1:length(indices)
for (indices{y})=1:5
answer=indices{1}+indices{2}+indices{3} ... ;
end end
-------------------


I'm not asking for a way to solve the problem of a+b+c ... more cleverly,
I'm just asking if there's a way to loop over all these different variables without typing them out individually. a+b+c .. was just a simple example to replace the big subroutine that I'm putting there.

Is the only way to do this by using the eval command and "poofing" variables into existence ??

Thanks




where at each

Tags for this Thread

Everyone's Tags:

Add a New Tag:

Separated by commas
Ex.: root locus, bode

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Tag Activity for This Thread
Tag Applied By Date/Time
eval Oleg Komarov 10 Jul, 2009 17:39:03
rssFeed for this Thread

Contact us at files@mathworks.com