Dynamic Variables

M

Marc Heiler

Is there any way in ruby to create dynamic variables?

counter = 52
box#{counter} = "cat and dogs"

There would be then a new variable
box52

Note that this is not a question whether someone should do it or not -
this is solely whether it is doable or not. Until today I thought it is
somehow possible with eval but I failed, so I assume it is not possible.
 
I

Igal Koshevoy

Marc said:
Is there any way in ruby to create dynamic variables?

counter = 52
box#{counter} = "cat and dogs"

There would be then a new variable
box52

Note that this is not a question whether someone should do it or not -
this is solely whether it is doable or not. Until today I thought it is
somehow possible with eval but I failed, so I assume it is not possible.
irb(main):010:0> counter = 52
=> 52
irb(main):011:0> eval "box#{counter} = 'cat and dogs'"
=> "cat and dogs"
irb(main):012:0> box52
=> "cat and dogs"

-igal
 
C

Calamitas

irb(main):010:0> counter = 52
=> 52
irb(main):011:0> eval "box#{counter} = 'cat and dogs'"
=> "cat and dogs"
irb(main):012:0> box52
=> "cat and dogs"

Now try the same thing in plain ruby without irb. Never trust irb on
things like these.

Dynamic variables as created by eval live in a separate, eval-specific
scope and can only be accessed through eval. This is a consequence of
Ruby deciding at "compile" time what's a local variable and what's
not. So, if you have code like this:

eval "a = 5"
p a

then in "p a", a is determined to be a method call before that code is
even run. The a is accessible through eval though:

eval "a = 5"
p eval("a")

Peter
 
I

Igal Koshevoy

Frederick said:
Although that doesn't work outside of irb. (although you can change
the value of an existing local variable like that)
See also
http://groups.google.com/group/comp...aaf698a0b9/e1c761b71b63b82e?#e1c761b71b63b82e
Thanks for catching the mistake and providing the link.


So there really is no way to get the "box52" variable directly? It's
only available within the context of an eval?

When I run the code below directly (not from IRB), the interpreter is
clearly seeing the "box52" local variable and keeping its state around,
but won't let me access it without wrapping an eval around it, which
seems wrong:

counter = 52
p local_variables # => ["counter"]
eval "box#{counter} = 'cat and dogs'"
p local_variables # => ["counter", "box52"]
p eval("box52") # => "cat and dogs"
p box52 # => undefined local variable or method `box52' for main:Object
(NameError)


I say "seems wrong" because I'm used to the following behavior:

# Python
counter = 52
eval(compile('box%s = "cat and dogs"' % counter, '<string>', 'exec'))
print box52 # => "cat and dogs"

# Perl
$counter = 52;
eval("\$box$counter = 'cat and dogs'");
print $box52, "\n"; # => "cat and dogs"

-igal
 
G

Gregory Seidman

Is there any way in ruby to create dynamic variables?

counter = 52
box#{counter} = "cat and dogs"

There would be then a new variable
box52

Note that this is not a question whether someone should do it or not -
this is solely whether it is doable or not. Until today I thought it is
somehow possible with eval but I failed, so I assume it is not possible.

I'm going to give you exactly what you didn't ask for: why this is a bad
idea. This is a discussion about Perl rather than Ruby, but it remains
relevant: http://perl.plover.com/varvarname.html

See the subsequent parts of the series for further discussion.

--Greg
 
M

Martin Boese

'Object' has a method to define instance variables:

irb(main):001:0> counter = 52
irb(main):002:0> self.instance_variable_set("@box#{counter}", 'cat and dogs')
=> "cat and dogs"
irb(main):003:0> @box52
=> "cat and dogs"


martin
 
S

stephen O'D

I'm going to give you exactly what you didn't ask for: why this is a bad
idea. This is a discussion about Perl rather than Ruby, but it remains
relevant:http://perl.plover.com/varvarname.html

See the subsequent parts of the series for further discussion.

--Greg

Here here - I remember reading that article way back - the basic point
of it is that if you want to create a variable on the fly, it probably
means you should be using a Hash.
 
C

Charles Oliver Nutter

Igal said:
# Python
counter = 52
eval(compile('box%s = "cat and dogs"' % counter, '<string>', 'exec'))
print box52 # => "cat and dogs"

# Perl
$counter = 52;
eval("\$box$counter = 'cat and dogs'");
print $box52, "\n"; # => "cat and dogs"

In python, local variables are not (necessarily) determined at
parse/compile time. They're slots in a local scope that can grow later on.

In Ruby, this behavior only exists for eval scopes. Ruby 1.8 shares a
single eval scope under any given normal scope across all evals in that
normal scope. Ruby 1.9 instantiates a new eval scope for each eval.

I don't know what Perl does.

- Charlie
 
I

Igal Koshevoy

Charles said:
In python, local variables are not (necessarily) determined at
parse/compile time. They're slots in a local scope that can grow later
on.

In Ruby, this behavior only exists for eval scopes. Ruby 1.8 shares a
single eval scope under any given normal scope across all evals in
that normal scope. Ruby 1.9 instantiates a new eval scope for each eval.

I don't know what Perl does.
Charles, thanks for the clarification about the scoping behaviors.


I suppose if I really want to pretend like I was dynamically injecting a
local variable into a local scope, and a class/instance variable didn't
weren't desirable, then I could resort to:

def set(name, value)
self.class.send:)attr_accessor, name)
self.send("#{name}=", value)
end

counter = 52
set "box#{counter}", "cat and dogs"
p box52 # => "cat and dogs"

-igal
 
C

Charles Oliver Nutter

Igal said:
I suppose if I really want to pretend like I was dynamically injecting a
local variable into a local scope, and a class/instance variable didn't
weren't desirable, then I could resort to:

def set(name, value)
self.class.send:)attr_accessor, name)
self.send("#{name}=", value)
end

counter = 52
set "box#{counter}", "cat and dogs"
p box52 # => "cat and dogs"

Yup, that would work except that for an attr_accessor on self you need
to qualify it with self.box52...so it wouldn't be quite seamless.

- Charlie
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,276
Latest member
Sawatmakal

Latest Threads

Top