Convert string into a variable object

Hi,
I have a string named "ruby". I want to create an empty object by that
name: @ruby

Is there a way to do this?

···

--
Posted via http://www.ruby-forum.com/.

Ad Ad wrote:

Hi,
I have a string named "ruby". I want to create an empty object by that
name: @ruby

Is there a way to do this?

Yes.
Also, it is most likely that there is an easier way to do what you want
to do.
What _do_ you want to do?

···

--
Posted via http://www.ruby-forum.com/\.

Aldric Giacomoni wrote:

Ad Ad wrote:

Hi,
I have a string named "ruby". I want to create an empty object by that
name: @ruby

Is there a way to do this?

Yes.
Also, it is most likely that there is an easier way to do what you want
to do.
What _do_ you want to do?

I have a file with a list of cities in it. The file is a daily feed and
the cities in it change daily.

I want to create a class which reads the file and creates the variables
with the city names.
File.open("file").each{ |x|
@"x" = 1 #I need a logic for this
end

this would give us @toronto = 1, @miami = 1, etc.

I have subclasses which would read user input and if that city variable
has been defined already then move ahead.
it would be a simple if statement
if @toronto
...
end

I could create a hash map too but this is the easiest way to do since it
doesnt require the creation of any sort of a container variable.

···

--
Posted via http://www.ruby-forum.com/\.

A much better way to do this would be to store the city names in a hash.
your code would then be:

File.open(@file). each do |x|
  @hash = true
end

later on you can then just do

if @hash[city]

Toon

···

On 07 Dec 2009, at 21:35, Ad Ad wrote:

Aldric Giacomoni wrote:

Ad Ad wrote:

Hi,
I have a string named "ruby". I want to create an empty object by that
name: @ruby

Is there a way to do this?

Yes.
Also, it is most likely that there is an easier way to do what you want
to do.
What _do_ you want to do?

I have a file with a list of cities in it. The file is a daily feed and
the cities in it change daily.

I want to create a class which reads the file and creates the variables
with the city names.
File.open("file").each{ |x|
@"x" = 1 #I need a logic for this
end

this would give us @toronto = 1, @miami = 1, etc.

I have subclasses which would read user input and if that city variable
has been defined already then move ahead.
it would be a simple if statement
if @toronto
...
end

I could create a hash map too but this is the easiest way to do since it
doesnt require the creation of any sort of a container variable.
--
Posted via http://www.ruby-forum.com/\.

you can use

File.open("file").each{ |x|
instance_variable_set "@#{x}", 1
end

···

On Tue, Dec 8, 2009 at 3:35 AM, Ad Ad <codetest123@gmail.com> wrote:

Aldric Giacomoni wrote:
> Ad Ad wrote:
>> Hi,
>> I have a string named "ruby". I want to create an empty object by that
>> name: @ruby
>>
>> Is there a way to do this?
>
> Yes.
> Also, it is most likely that there is an easier way to do what you want
> to do.
> What _do_ you want to do?

I have a file with a list of cities in it. The file is a daily feed and
the cities in it change daily.

I want to create a class which reads the file and creates the variables
with the city names.
File.open("file").each{ |x|
@"x" = 1 #I need a logic for this
end

this would give us @toronto = 1, @miami = 1, etc.

I have subclasses which would read user input and if that city variable
has been defined already then move ahead.
it would be a simple if statement
if @toronto
...
end

I could create a hash map too but this is the easiest way to do since it
doesnt require the creation of any sort of a container variable.
--
Posted via http://www.ruby-forum.com/\.

I have a file with a list of cities in it. The file is a daily feed and
the cities in it change daily.

[snip]

this would give us @toronto = 1, @miami = 1, etc.

Is 1 significant? That is, are you trying to count the number of cities, or
are you just trying to set them to true?

I have subclasses which would read user input and if that city variable
has been defined already then move ahead.
it would be a simple if statement
if @toronto
...
end

In that case, it would be _much_ more readable if you did

@toronto = true

rather than

@toronto = 1

They'll do the same thing here, but consider this:

@toronto = 0

That would be false, right? Wrong. Anything that's not false or nil is a true
value in Ruby. You're MUCH better off explicitly using true and false, if
that's really what you wanted.

If it was meant to be a count, you'd probably want something like:

if @toronto > 0

but I have no idea why a count would make sense here, anyway.

I could create a hash map too

Yes, you should do that. The downsides of using instance variables for that
are much larger than the downsides of doing a little extra typing with:

if @cities['toronto']

but this is the easiest way to do since it

No it's not. You had to come here and ask if it was even possible. You already
know a hash map is possible, and yo probably already know how to do it.

Just in case someone tells you how to use variables instead, here's one very
simple reason it's a bad idea: Instance variables have symbols assigned to
them. Last I checked, symbols aren't garbage collected, so doing it your way
will result in a (very small) memory leak in your program. That won't happen
with a hash of strings.

doesnt require the creation of any sort of a container variable.

Why is this a problem?

I mean, is it the _creation_ of this that's holding you back? That's a single
line:

@cities = {}

Put it in initialize.

···

On Monday 07 December 2009 02:35:39 pm Ad Ad wrote:

Toon Willems wrote:

to do.

doesnt require the creation of any sort of a container variable.
--
Posted via http://www.ruby-forum.com/\.

A much better way to do this would be to store the city names in a hash.
your code would then be:

File.open(@file). each do |x|
  @hash = true
end

Would it not be better to convert to symbols? That is:

File.open(@file). each do |x|
   @hash[x.strip.to_sym] = true
end

if @hash[:toronto]
or
if @hash[:"palo alto"]

or

if @hash[city.to_sym]

···

On 07 Dec 2009, at 21:35, Ad Ad wrote:

later on you can then just do

if @hash[city]

Toon

--
Posted via http://www.ruby-forum.com/\.

Hi,

I would think it depends entirely on the use case.

You're going to need to hit 8MB memory usage before ruby is going to
sweep and collect those string objects.

Every time you access a value in your hash by key, that is a new string
object. It could be more efficient to use symbols to stay *under* a
threshold, rather then go over it by creating new string objects every
time you want to access a value in your hash.

Thanks,
Rob

···

--
Posted via http://www.ruby-forum.com/.

Not if the cities are changing every day. Remember, symbols are never garbage
collected -- they should _only_ be used when there is a finite and predictable
number of possible symbols you might create.

Otherwise, you have a slow memory leak -- and especially for something like
this, you're not really going to get a performance boost out of it.

···

On Tuesday 08 December 2009 01:03:31 am Steve Wilhelm wrote:

Toon Willems wrote:
> On 07 Dec 2009, at 21:35, Ad Ad wrote:
>>> to do.
>>
>> doesnt require the creation of any sort of a container variable.
>
> A much better way to do this would be to store the city names in a hash.
> your code would then be:
>
> File.open(@file). each do |x|
> @hash = true
> end

Would it not be better to convert to symbols?

HI --

···

On Tue, 8 Dec 2009, Steve Wilhelm wrote:

Toon Willems wrote:

On 07 Dec 2009, at 21:35, Ad Ad wrote:

to do.

doesnt require the creation of any sort of a container variable.
--
Posted via http://www.ruby-forum.com/\.

A much better way to do this would be to store the city names in a hash.
your code would then be:

File.open(@file). each do |x|
  @hash = true
end

Would it not be better to convert to symbols? That is:

File.open(@file). each do |x|
  @hash[x.strip.to_sym] = true
end

if @hash[:toronto]
or
if @hash[:"palo alto"]

or

if @hash[city.to_sym]

In addition to the garbage collection issue that David M. pointed out,
symbols seem an odd choice to me for city names. I always think of
symbols as appropriate for label-like functionality and values taken
from a limited set. Strings are a better choice for general
representation of text.

David

--
David A. Black
Senior Developer, Cyrus Innovation Inc.
THE COMPLEAT RUBYIST, Ruby training with Black/Brown/McAnally!
January 22-23, Tampa, Florida
Info and registration at http://www.thecompleatrubyist.com

I would certainly use String for city names. Hard encoding city names
in classes which would be regenerated over and over again is not a
good solution. Basically, you want to stick all city names as keys in
a Hash and work from there. The mere fact that Ruby is able to
generate local, instance or global variables at runtime does not mean
it is a proper means in all cases. The use case at hand does not call
for meta programming - it just needs a data structure which can work
with appropriate key values. A Hash seems like a good fit here.

My 0.02EUR.

Kind regards

robert

···

2009/12/8 David A. Black <dblack@rubypal.com>:

HI --

On Tue, 8 Dec 2009, Steve Wilhelm wrote:

Toon Willems wrote:

On 07 Dec 2009, at 21:35, Ad Ad wrote:

to do.

doesnt require the creation of any sort of a container variable.
--
Posted via http://www.ruby-forum.com/\.

A much better way to do this would be to store the city names in a hash.
your code would then be:

File.open(@file). each do |x|
@hash = true
end

Would it not be better to convert to symbols? That is:

File.open(@file). each do |x|
@hash[x.strip.to_sym] = true
end

if @hash[:toronto]
or
if @hash[:"palo alto"]

or

if @hash[city.to_sym]

In addition to the garbage collection issue that David M. pointed out,
symbols seem an odd choice to me for city names. I always think of
symbols as appropriate for label-like functionality and values taken
from a limited set. Strings are a better choice for general
representation of text.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

David Masover wrote:

> @hash = true
> end

Would it not be better to convert to symbols?

Not if the cities are changing every day. Remember, symbols are never
garbage
collected -- they should _only_ be used when there is a finite and
predictable

I would have thought number of cities over time would be finite and
predictable. Granted, the number of cities is probably in the tend or
hundreds of thousands.

So symbols would be appropriate if instead of cities, adad was reading a
text file of state names? How about country names (currently under 200)?
I ask, in an attempt to gauge what is typically considered the accepted
threshold for using symbols.

···

On Tuesday 08 December 2009 01:03:31 am Steve Wilhelm wrote:

number of possible symbols you might create.

Otherwise, you have a slow memory leak -- and especially for something
like
this, you're not really going to get a performance boost out of it.

--
Posted via http://www.ruby-forum.com/\.

Steve Wilhelm wrote:

I would have thought number of cities over time would be finite and
predictable. Granted, the number of cities is probably in the tend or
hundreds of thousands.

So symbols would be appropriate if instead of cities, adad was reading a
text file of state names? How about country names (currently under 200)?
I ask, in an attempt to gauge what is typically considered the accepted
threshold for using symbols.

That's certainly easy enough to create - get some list of cities..
http://answers.google.com/answers/threadview/id/774429.html
http://answers.google.com/answers/threadview/id/779905.html
http://www.maxmind.com/app/worldcities

Parse it.. Make symbols.. Check our how your computer's RAM looks, and
how well it handles the hash / array / whatever data structure you've
been using (if any, since you can just create symbols, after all...)

Let us know :wink:

···

--
Posted via http://www.ruby-forum.com/\.

Now perhaps I'm missing something, but the impression I got was that
while the contents of the file changes daily, he doesn't want to remove
old cities. Rather he wants to ensure he's not creating duplicates. My
solution (to the problem as I understand it) would be to use sets, but
if he's not actually wanting to remove anything, I don't think Strings
vs. Symbols should matter.

Example of set solution:
irb(main):001:0> require 'set'
=> true
irb(main):002:0> cities=Set.new
=> #<Set: {}>
irb(main):003:0> cities << 'Austin, Texas'
=> #<Set: {"Austin, Texas"}>
irb(main):004:0> cities << 'Boring, Oregon'
=> #<Set: {"Austin, Texas", "Boring, Oregon"}>
irb(main):005:0> cities << 'Boise, Idaho'
=> #<Set: {"Austin, Texas", "Boring, Oregon", "Boise, Idaho"}>
irb(main):006:0> cities << 'Boring, Oregon'
=> #<Set: {"Austin, Texas", "Boring, Oregon", "Boise, Idaho"}>
irb(main):008:0> cities.include? 'Boring, Oregon'
=> true
irb(main):009:0>

Is there something I'm missing?

···

-----Original Message-----
From: Robert Klemme [mailto:shortcutter@googlemail.com]

2009/12/8 David A. Black <dblack@rubypal.com>:
> HI --
>
> On Tue, 8 Dec 2009, Steve Wilhelm wrote:
>
>> Toon Willems wrote:
>>>
>>> On 07 Dec 2009, at 21:35, Ad Ad wrote:
>>>
>>>>> to do.
>>>>
>>>> doesnt require the creation of any sort of a container variable.
>>>> --
>>>> Posted via http://www.ruby-forum.com/\.
>>>>
>>>
>>> A much better way to do this would be to store the city names in a
hash.
>>> your code would then be:
>>>
>>> File.open(@file). each do |x|
>>> @hash = true
>>> end
>>
>> Would it not be better to convert to symbols? That is:
>>
>> File.open(@file). each do |x|
>> @hash[x.strip.to_sym] = true
>> end
>>
>> if @hash[:toronto]
>> or
>> if @hash[:"palo alto"]
>>
>> or
>>
>> if @hash[city.to_sym]
>
> In addition to the garbage collection issue that David M. pointed
out,
> symbols seem an odd choice to me for city names. I always think of
> symbols as appropriate for label-like functionality and values taken
> from a limited set. Strings are a better choice for general
> representation of text.

I would certainly use String for city names. Hard encoding city names
in classes which would be regenerated over and over again is not a
good solution. Basically, you want to stick all city names as keys in
a Hash and work from there. The mere fact that Ruby is able to
generate local, instance or global variables at runtime does not mean
it is a proper means in all cases. The use case at hand does not call
for meta programming - it just needs a data structure which can work
with appropriate key values. A Hash seems like a good fit here.

David Masover wrote:

> Not if the cities are changing every day. Remember, symbols are never
> garbage
> collected -- they should _only_ be used when there is a finite and
> predictable

I would have thought number of cities over time would be finite and
predictable. Granted, the number of cities is probably in the tend or
hundreds of thousands.

So symbols would be appropriate if instead of cities, adad was reading a
text file of state names?

Nope. A typo or an error in the file, and you've got a problem again. It's
similar to when you've got any sort of external input which you want to
compare to a finite list of values. It might be tempting to do this:

Values = [:one, :two, :three, :four]
...
if Values.include? input_value.to_sym

What you should be doing is this:

Values = ['one','two','three','four'].map(&:freeze).freeze
...
if Values.include? input_value

If it's still not efficient enough (if there are hundreds of values), put them
in a Set or a Hash, but that's even more reason not to convert input to syms.

I'd only do it that way you're suggesting if the file in question was part of
the source distribution, but it sounds like it's coming from an external
service.

How about country names (currently under 200)?
I ask, in an attempt to gauge what is typically considered the accepted
threshold for using symbols.

In my opinion, the threshold of using symbols is whenever it's a finite number
that's generated only from trusted sources -- generally, stuff inside your
application source code.

It also matters how it's being used -- as David Black and Robert Klemme point
out, symbols are generally for labels. They're what's used to refer to
functions and variables by "name" in Ruby. Their other major use is for hashes
of options passed around -- essentially, keyword arguments.

It might also help to think of Symbols as Enum values. Let me put it this way
-- in other languages, like C and Java, you might have a fixed number of
values you might want to work with. For example, suppose I want to open a file
read, write, or both. It's inefficient to actually pass the strings "read",
"write", or "read/write" with every file open, so instead, I might pass an
integer, 1, 2, or 3. But that's annoying to work with, so instead, I'd define
a constant:

#define READ 1
#define WRITE 2
#define READWRITE 3

Now I can do something like:

open("foo", READ)

Then, inside the open function, you'd have something like:

case mode
  when READ
  when WRITE
...

All of which is just shorthand for:

open("foo", 1)

and

case mode
  when 1
  when 2
...

This is vastly oversimplified, and not how it's actually done, but it works.
This is also such a common pattern that languages have shortcuts for it. I'm
working from memory here, so the syntax is probably wrong, but the idea holds:

enum { READ, WRITE, READWRITE }

open("foo", READ)

The enum will automatically assign a unique integer value to each of READ,
WRITE, and READWRITE. As long as that same enum is visible to the code of the
open function, and to the code calling it, the number assigned to READ, WRITE,
and READWRITE will be the same each time.

Note that at this point, you really don't have to care what number it is, just
that it's unique, and that doing it this way is just as efficient as manually
specifying a number.

And since it doesn't matter, there's no reason passing 1 should be more
efficient than passing 3085, or anything, as long as it's still a 32-bit
integer. (Or 64-bit, if you're on a 64-bit platform.) If you were really
strapped for space, you could use a single byte value, but there is actually a
real possibility that won't be enough, depending on your application, and you
want to be backwards compatible. So an int makes sens, and besides, enum is
doing all the work for you.

So, symbols -- a concept from Lisp, actually -- take this just a step farther.
Rather than assigning a number that's just unique for that function (READ-1,
WRITE-2, etc), you get a number that's globally unique. When you type

:foo

...what you're really doing is getting a unique integer, which Ruby will
replace any occurrance of the symbol :foo with, anywhere in your source code.
Again, it's oversimplifying -- it's probably implemented as an integer, but
you'll see it as a Symbol object. The entire point of this is so that you can
guarantee that the following two things will be true:

:foo == :foo
:foo != :bar

And of course, you can do case structures using symbols, you can use them in
hash values, and so on.

And because Ruby is reflective, you can do things like:

"foo".to_sym

But scroll back up and look at the "enum" example. This kind of monkying is
properly metaprogramming -- it would be like writing a program that generates
enum statements for a header.

Sometimes, it might actually be appropriate. An obvious example is an ORM --
an intelligent ORM can read the database schema and create methods named after
database columns. You'll get those column names as strings, and you'll turn
them into symbols. You might even be fancy, like Rails, and do some string
manipulation (pluralize them, etc) and create some more methods.

That's not entirely a new idea, either. If this was a compiled language, you'd
probably have a tool that took some specification (maybe XML... ugh) and
converted it into both SQL statements to create that database, and source code
to access it. The main difference is that Ruby is dynamic enough to do this at
runtime, just-in-time, rather than having to actually generate source code.

But the concepts are the same.

Here's a quick rule of thumb:

- Am I metaprogramming?
- Are these keyword arguments, or some sort of options hash?
- Are the symbols created with the colon notation (:foo)?

If you answered yes to any of those, symbols are fine. If you answered no to
all of them, probably not.

phew! I think I need a blog.

···

On Tuesday 08 December 2009 02:11:53 pm Steve Wilhelm wrote:

Maybe. I was talking about the approach to generate variable names. City names in this case are part of the domain data. They are read over and over again and apparently the task of the program is to manage city names somehow.

Variable names on the other hand are part of the application structure. You'd rather have a variable @city_name here than a variable @new_york. It does not make much sense to regenerate classes over and over again (at least that seems to be what OP wants to do) does not really make sense.

The question what is added or removed which you discussed is a completely different one. Whether a Set or a Hash is a more appropriate data structure depends on the use case which I haven't seen much detail of. (Maybe I'm missing something as well.)

Kind regards

  robert

···

On 12/08/2009 09:57 PM, Walton Hoops wrote:

-----Original Message-----
From: Robert Klemme [mailto:shortcutter@googlemail.com]

2009/12/8 David A. Black <dblack@rubypal.com>:

HI --

On Tue, 8 Dec 2009, Steve Wilhelm wrote:

Toon Willems wrote:

On 07 Dec 2009, at 21:35, Ad Ad wrote:

to do.

doesnt require the creation of any sort of a container variable.
--
Posted via http://www.ruby-forum.com/\.

A much better way to do this would be to store the city names in a

hash.

your code would then be:

File.open(@file). each do |x|
@hash = true
end

Would it not be better to convert to symbols? That is:

File.open(@file). each do |x|
@hash[x.strip.to_sym] = true
end

if @hash[:toronto]
or
if @hash[:"palo alto"]

or

if @hash[city.to_sym]

In addition to the garbage collection issue that David M. pointed

out,

symbols seem an odd choice to me for city names. I always think of
symbols as appropriate for label-like functionality and values taken
from a limited set. Strings are a better choice for general
representation of text.

I would certainly use String for city names. Hard encoding city names
in classes which would be regenerated over and over again is not a
good solution. Basically, you want to stick all city names as keys in
a Hash and work from there. The mere fact that Ruby is able to
generate local, instance or global variables at runtime does not mean
it is a proper means in all cases. The use case at hand does not call
for meta programming - it just needs a data structure which can work
with appropriate key values. A Hash seems like a good fit here.

Now perhaps I'm missing something, but the impression I got was that while the contents of the file changes daily, he doesn't want to remove
old cities. Rather he wants to ensure he's not creating duplicates. My solution (to the problem as I understand it) would be to use sets, but if he's not actually wanting to remove anything, I don't think Strings
vs. Symbols should matter.

Example of set solution:
irb(main):001:0> require 'set'
=> true
irb(main):002:0> cities=Set.new
=> #<Set: {}>
irb(main):003:0> cities << 'Austin, Texas'
=> #<Set: {"Austin, Texas"}>
irb(main):004:0> cities << 'Boring, Oregon'
=> #<Set: {"Austin, Texas", "Boring, Oregon"}>
irb(main):005:0> cities << 'Boise, Idaho'
=> #<Set: {"Austin, Texas", "Boring, Oregon", "Boise, Idaho"}>
irb(main):006:0> cities << 'Boring, Oregon'
=> #<Set: {"Austin, Texas", "Boring, Oregon", "Boise, Idaho"}>
irb(main):008:0> cities.include? 'Boring, Oregon'
=> true
irb(main):009:0>

Is there something I'm missing?

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/