5

I am trying to dynamically set (not create, it already has to exist) a global ruby variable in a method. The variable name is determined from the passed symbol. What I am currently doing is the following:

def baz(symbol)
  eval("$#{symbol}_bar = 42")
end

$foo_bar = 0
baz(:foo)
puts $foo_bar # => 42  

But to me, this kind of feels very wrong. Is this the way to do this? Or can it be done differently? Also, I don't know how evals perform in ruby. Does it run much slower than

$foo_bar = 42
4
  • 2
    Using variables whose names are generated on the fly is generally discouraged because of it makes it harder when maintaining/debugging the code. Perl also has the ability to do it, and it used to be a common practice, but over the years that community has stepped away from it. All in all its a cute trick, more of a curiosity, and something I'd avoid if at all possible. That said, there are times when it is helpful for dynamically generating code, but you gotta be aware of the dragons lying in wait. In Ruby there are better ways than using eval. Commented Mar 26, 2011 at 22:59
  • @the Tin Man: This is not for creating global variables, only to modify them. Maybe I should add a check if the global variable already exists, before trying to assign a new value?! Commented Mar 26, 2011 at 23:21
  • 1
    That would be a good idea. If your code to generate the variable names were to get the name wrong you'd be creating new globals, which is no fun. Commented Mar 27, 2011 at 0:00
  • You are missing a close parenthesis. Commented Mar 27, 2011 at 4:00

2 Answers 2

2

The method looks fine to me. This guy says that eval efficiency is much worse, though the post is 3 years old.

I will point out that this method suggests you have a lot of global variables, which is generally a code smell if the code base is significant.

Sign up to request clarification or add additional context in comments.

1 Comment

I see your point. What I am doing is a (more or less 1:1) rewrite of the perl blogging software Blosxom in Ruby (which has ~500 LOC total), so I am pretty much copying an existing structure. Personally I always avoid using global variables ;)
1

If you can use an instance variable instead, there is Object#instance_variable_set.

  def baz(symbol)
    instance_variable_set("@#{symbol}_bar", 42)
  end

Note that it only accepts variable names that can be accepted as an instance variable (starting with @). If you put anything else in the first argument, it will return an error. For the global variable counterpart to it, there is a discussion here: Forum: Ruby

Either way, you also have the problem of accessing the variable. How are you going to do that?

2 Comments

The script knows about all its variables and accesses them normally. I want to do the "setting" part dynamically, because the logic inside #baz() is more complex and I don't want to copy and paste it all over the script.
Also, +1 for the link. I knew about instance_variable_set, but it throws an exception if you enter a variable name with a $, you should fix that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.