Despite reading "Understanding Ruby Symbols", I'm still confused by the representation of the data in memory when it comes to using symbols. If a symbol, two of them contained in different objects, exist in the same memory location, then how is it that they contain different values? I'd have expected the same memory location to contain the same value.
This a quote from the link:
Unlike strings, symbols of the same name are initialized and exist in memory only once during a session of ruby
I don't understand how it manages to differentiate the values contained in the same memory location.
Consider this example:
patient1 = { :ruby => "red" }
patient2 = { :ruby => "programming" }
patient1.each_key {|key| puts key.object_id.to_s}
3918094
patient2.each_key {|key| puts key.object_id.to_s}
3918094
patient1 and patient2 are both hashes, that's fine. :ruby however is a symbol. If we were to output the following:
patient1.each_key {|key| puts key.to_s}
Then what will be output? "red", or "programming"?
Forgetting hashes for a second, I'm thinking a symbol is a pointer to a value. The questions I have are:
Can I assign a value to a symbol?
Is a symbol just a pointer to a variable with a value in it?
If symbols are global, does that mean a symbol always points to one thing?
Consider this:
x = :sym
y = :sym
(x.__id__ == y.__id__ ) && ( :sym.__id__ == x.__id__) # => true
x = "string"
y = "string"
(x.__id__ == y.__id__ ) || ( "string".__id__ == x.__id__) # => false
So, however you create a symbol object, as long as its contents are the same, it will refer to the same object in memory. This is not a problem because a symbol is an immutable object. Strings are mutable.
(In response to the comment below)
In the original article, the value is not being stored in a symbol, it is being stored in a hash. Consider this:
hash1 = { "string" => "value"}
hash2 = { "string" => "value"}
This creates six objects in the memory -- four string objects and two hash objects.
hash1 = { :symbol => "value"}
hash2 = { :symbol => "value"}
This only creates five objects in memory -- one symbol, two strings and two hash objects.
I was able to grock symbols when I thought of it like this. A Ruby string is an object that has a bunch of methods and properties. People like to use strings for keys, and when the string is used for a key then all those extra methods aren't used. So they made symbols, which are string objects with all the functionality removed, except that which is needed for it to be a good key.
Just think of symbols as constant strings.
The symbol :ruby does not contain "red" or "programming". The symbol :ruby is just the symbol :ruby. It is your hashes, patient1 and patient2 that each contain those values, in each case pointed to by the same key.
Think about it this way: If you go into the living room on christmas morning, and see two boxes with a tag on them that say "Kezzer" on them. On has socks in it, and the other has coal. You're not going to get confused and ask how "Kezzer" can contain both socks and coal, even though it is the same name. Because the name isn't containing the (crappy) presents. It's just pointing at them. Similarly, :ruby doesn't contain the values in your hash, it just points at them.
You might be presuming that the declaration you've made defines the value of a Symbol to be something other than what it is. In fact, a Symbol is just an "internalized" String value that remains constant. It is because they are stored using a simple integer identifier that they are frequently used as that is more efficient than managing a large number of variable-length strings.
Take the case of your example:
patient1 = { :ruby => "red" }
This should be read as: "declare a variable patient1 and define it to be a Hash, and in this store the value 'red' under the key (symbol 'ruby')"
Another way of writing this is:
patient1 = Hash.new
patient1[:ruby] = 'red'
puts patient1[:ruby]
# 'red'
As you are making an assignment it is hardly surprising that the result you get back is identical to what you assigned it with in the first place.
The Symbol concept can be a little confusing as it's not a feature of most other languages.
Each String object is distinct even if the values are identical:
[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
puts v.inspect + ' ' + v.object_id.to_s
end
# "foo" 2148099960
# "foo" 2148099940
# "foo" 2148099920
# "bar" 2148099900
# "bar" 2148099880
# "bar" 2148099860
Every Symbol with the same value refers to the same object:
[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
puts v.inspect + ' ' + v.object_id.to_s
end
# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668
Converting strings to symbols maps identical values to the same unique Symbol:
[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
v = v.to_sym
puts v.inspect + ' ' + v.object_id.to_s
end
# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668
Likewise, converting from Symbol to String creates a distinct string every time:
[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
v = v.to_s
puts v.inspect + ' ' + v.object_id.to_s
end
# "foo" 2148097820
# "foo" 2148097700
# "foo" 2148097580
# "bar" 2148097460
# "bar" 2148097340
# "bar" 2148097220
You can think of Symbol values as being drawn from an internal Hash table and you can see all values that have been encoded to Symbols using a simple method call:
Symbol.all_values
# => [:RUBY_PATCHLEVEL, :vi_editing_mode, :Separator, :TkLSHFT, :one?, :setuid?, :auto_indent_mode, :setregid, :back, :Fail, :RET, :member?, :TkOp, :AP_NAME, :readbyte, :suspend_context, :oct, :store, :WNOHANG, :#seek, :autoload, :rest, :IN_INPUT, :close_read, :type, :filename_quote_characters=, ...
As you define new symbols either by the colon-notation or by using .to_sym this table will grow.
Symbols are not pointers. They do not contain values. Symbols simply are. :ruby is the symbol :ruby and that's all there is to it. It doesn't contain a value, it doesn't do anything, it just exists as the symbol :ruby. The symbol :ruby is a value just like the number 1 is. It doesn't point to another value any more than the number 1 does.
patient1.each_key {|key| puts key.to_s}
Then what will be output? "red", or
"programming"?
Neither, it will output "ruby".
You're confusing symbols and hashes. They aren't related, but they're useful together. The symbol in question is :ruby; it has nothing to do with the values in the hash, and it's internal integer representation will always be the same, and it's "value" (when converted to a string) will always be "ruby".
In short
Symbols solve the problem of creating human readable, immutable representations that also have the benefit of being simpler for the runtime to lookup than strings. Think of it like a name or label that can be reused.
Why :red is better than "red"
In dynamic object oriented languages you create complex, nested data structures with readable references. The hash is a common use case where you map values to unique keys — unique, at least, to each instance. You can't have more than one "red" key per hash.
However it would be more processor efficient to use a numeric index instead of string keys. So symbols were introduced as a compromise between speed and readability. Symbols resolve much easier than the equivalent string. By being human readable and easy for the runtime to resolve symbols are an ideal addition to a dynamic language.
Benefits
Since symbols are immutable they can be shared across the runtime. If two hash instances have a common lexicographic or semantic need for a red item the symbol :red would use roughly half the memory that the string "red" would have required for two hashes.
Since :red always resolves back to the same location in memory it can be reused across a hundred hash instances with almost no increase in memory, whereas using "red" will add a memory cost since each hash instance would need to store the mutable string upon creation.
Not sure how Ruby actually implements symbols/string but clearly a symbol offers less implementation overhead in the runtime since it's a fixed representation. Plus symbols takes one less character to type than a quoted string and less typing is the eternal pursuit of true Rubyists.
Summary
With a symbol like :red you get the readability of string representation with less overhead due to the cost of string comparison operations and the need to store each string instance in memory.
I would recommend reading the Wikipedia article on hash tables - I think it will help you get a sense of what {:ruby => "red"} really means.
Another exercise that might help your understanding of the situation: consider {1 => "red"}. Semantically, this doesn't mean "set the value of 1 to "red"", which is impossible in Ruby. Rather, it means "create a Hash object, and store the value "red" for the key 1.
patient1 = { :ruby => "red" }
patient2 = { :ruby => "programming" }
patient1.each_key {|key| puts key.object_id.to_s}
3918094
patient2.each_key {|key| puts key.object_id.to_s}
3918094
patient1 and patient2 are both hashes, that's fine. :ruby however is a symbol. If we were to output the following:
patient1.each_key {|key| puts key.to_s}
Then what will be output? "red", or "programming"?
Neither, of course. The output will be ruby. Which, BTW, you could have found out in less time than it took you to type the question, by simply typing it into IRB instead.
Why would it be red or programming? Symbols always evaluate to themselves. The value of the symbol :ruby is the symbol :ruby itself and the string representation of the symbol :ruby is the string value "ruby".
[BTW: puts always converts its arguments to strings, anyway. There's no need to call to_s on it.]
I'm new to Ruby, but I think (hope?) this is a simple way to look at it...
A symbol is not a variable or a constant. It doesn't stand in for, or point to, a value. A symbol IS a value.
All it is, is a string without the object overhead. The text and only the text.
So, this:
"hellobuddy"
Is the same as this:
:hellobuddy
Except you can't do, for example, :hellobuddy.upcase. It's the string value and ONLY the string value.
Likewise, this:
greeting =>"hellobuddy"
Is the same as this:
greeting => :hellobuddy
But, again, without the string object overhead.
One easy way to wrap your head around this is to think, "what if I were using a string rather than a symbol?
patient1 = { "ruby" => "red" }
patient2 = { "ruby" => "programming" }
It isn't confusing at all, right?
You're using "ruby" as a key in a hash.
"ruby" is a string literal, so that is the value. The memory address, or pointer, is not available to you.
Every time you invoke "ruby", you are creating a new instance of it, that is, creating a new memory cell containing the same value - "ruby".
The hash then goes "what's my key value? Oh it's "ruby". Then maps that value to "red" or "programming".
In other words, :ruby doesn't dereference to "red" or "programming".
The hash maps :ruby to "red" or "programming".
Compare that to if we use symbols
patient1 = { :ruby => "red" }
patient2 = { :ruby => "programming" }
The value of :ruby is also "ruby", effectively.
Why? Because symbols are essentially string constants.
Constants don't have multiple instances. It's the same memory address. And a memory address has a certain value, once dereferenced. For symbols, the pointer name is the symbol, and the dereferenced value is a string, which matches the symbol name, in this case, "ruby".
When in a hash, you are not using the symbol, the pointer, but the deferenced value. You're not using :ruby, but "ruby".
The hash then looks up for key "ruby", the value is "red" or "programming", depending on how you defined the hash.
The paradigm shift and take-home concept is that a symbol's value is a completely separate concept from a value mapped to by a hash, given a key of that hash.
Related
I heard that two symbols with the same name create only one memory area, but two strings with the same content create two memory areas.
What is the use of symbols?
Is symbol like a variable? If so, how can I assign a value to a symbol?
If I allocate memory only once for symbols with the same name, what am I doing with the symbols?
Ok, so the misunderstanding probably stems from this:
A symbol is not a variable, it is a value. like 9 is a value that is a number.
A symbol is a value that is kinda of roughly a string... it's just not a string that you can change... and because you can't change it, we can use a shortcut -> all symbols with the same name/value are stored in the same memory-spot (to save space).
You store the symbol into a variable, or use the value somewhere - eg as the key of a hash.... this last is probably one of the most common uses of a symbol.
you make a hash that contains key-value pairs eg:
thing_attrs = {:name => "My thing", :colour => "blue", :size => 6}
thing_attrs[:colour] # 'blue'
In this has - the symbols are the keys you can use any object as a key, but symbols are good to use as they use english words, and are thus easy to understand what you're storing/fetching... much better than, say numbers. Imagine you had:
thing_attrs = {0 => "My thing", 1 => "blue", 2 => 6}
thing_attrs[1] # => "blue"
It would be annoying and hard to remember that attribute 1 is the colour... it's much nicer to give names that you can read when you're reading the code. Thus we have two options: a string, or a symbol.
There would be very little difference between the two. A string is definitely usable eg:
thing_attrs = {"name" => "My thing", "colour" => "blue", "size" => 6}
thing_attrs["colour"] # 'blue'
except that as we know... symbols use less memory. Not a lot less, but enough less that in a large program, over time, you will notice it.
So it has become a ruby-standard to use symbols instead.
A Symbol is the most basic Ruby object you can create. It's just a name and an internal ID. Symbols are useful because a given symbol name refers to the same object throughout a Ruby program. Symbols are more efficient than strings. Two strings with the same contents are two different objects, but for any given name there is only one Symbol object. This can save both time and memory.
# p039symbol.rb
# use the object_id method of class Object
# it returns an integer identifier for an object
puts "string".object_id
puts "string".object_id
puts :symbol.object_id
puts :symbol.object_id
>ruby p039symbol.rb
21066960
21066930
132178
132178
>Exit code: 0
I find it most helpful to think of symbols as strings without all the fancy string features.
Their main use is as the name of other things in your program.
For example, say you have a hash of user information.
You could do
user = { 'name' => 'Tim', 'age' => 20 }
Here the hash keys are strings.
This is fine, but it's really overkill.
Strings have lots of fancy methods like substitution and smart capitalization, and they are mutable (i.e. string objects can be changed in place).
You are never going to change hash keys, so you don't need any of that.
Thus, it's better just to use symbols
user = { :name => 'Tim', :age => 20 }
Another place symbols show up is referring to class methods.
Say I have the following class
class Foo
def initialize(bar)
#bar = bar
end
end
If I need access to the value of #bar from outside of Foo I need to add a getter method to Foo.
That would look like this
class Foo
def initialize(bar)
#bar = bar
end
def bar
bar
end
end
However, this is a pretty common thing to want to do, so ruby provides shorthand as follows
class Foo
attribute_reader :bar
def initialize(bar)
#bar = bar
end
end
This tells Foo to create for us the method we added by hand in the previous version.
As you can see, we refer to the #bar variable using a symbol.
In answer to your second question, no, a symbol is not a variable.
You can't "assign it a value."
However, as you can see, symbols can sometimes be used to refer to variables.
According to the specification, strings that are used as a key to a hash are duplicated and frozen. Other mutable objects do not seem to have such special consideration. For example, with an array key, the following is possible.
a = [0]
h = {a => :a}
h.keys.first[0] = 1
h # => {[1] => :a}
h[[1]] # => nil
h.rehash
h[[1]] # => :a
On the other hand, a similar thing cannot be done with a string key.
s = "a"
h = {s => :s}
h.keys.first.upcase! # => RuntimeError: can't modify frozen String
Why is string designed to be different from other mutable objects when it comes to a hash key? Is there any use case where this specification becomes useful? What other consequences does this specification have?
I actually have a use case where absence of such special specification about strings may be useful. That is, I read with the yaml gem a manually written YAML file that describes a hash. the keys may be strings, and I would like to allow case insensitivity in the original YAML file. When I read a file, I might get a hash like this:
h = {"foo" => :foo, "Bar" => :bar, "BAZ" => :baz}
And I want to normalize the keys to lower case to get this:
h = {"foo" => :foo, "bar" => :bar, "baz" => :baz}
by doing something like this:
h.keys.each(&:downcase!)
but that returns an error for the reason explained above.
In short it's just Ruby trying to be nice.
When a key is entered in a Hash, a special number is calculated, using the hash method of the key. The Hash object uses this number to retrieve the key. For instance, if you ask what the value of h['a'] is, the Hash calls the hash method of string 'a' and checks if it has a value stored for that number. The problem arises when someone (you) mutates the string object, so the string 'a' is now something else, let's say 'aa'. The Hash would not find a hash number for 'aa'.
The most common types of keys for hashes are strings, symbols and integers. Symbols and integers are immutable, but strings are not. Ruby tries to protect you from the confusing behaviour described above by dupping and freezing string keys. I guess it's not done for other types because there could be nasty performance side effects (think of large arrays).
Immutable keys make sense in general because their hash codes will be stable.
This is why strings are specially-converted, in this part of MRI code:
if (RHASH(hash)->ntbl->type == &identhash || rb_obj_class(key) != rb_cString) {
st_insert(RHASH(hash)->ntbl, key, val);
}
else {
st_insert2(RHASH(hash)->ntbl, key, val, copy_str_key);
}
In a nutshell, in the string-key case, st_insert2 is passed a pointer to a function that will trigger the dup and freeze.
So if we theoretically wanted to support immutable lists and immutable hashes as hash keys, then we could modify that code to something like this:
VALUE key_klass;
key_klass = rb_obj_class(key);
if (key_klass == rb_cArray || key_klass == rb_cHash) {
st_insert2(RHASH(hash)->ntbl, key, val, freeze_obj);
}
else if (key_klass == rb_cString) {
st_insert2(RHASH(hash)->ntbl, key, val, copy_str_key);
}
else {
st_insert(RHASH(hash)->ntbl, key, val);
}
Where freeze_obj would be defined as:
static st_data_t
freeze_obj(st_data_t obj)
{
return (st_data_t)rb_obj_freeze((VALUE) obj);
}
So that would solve the specific inconsistency that you observed, where the array-key was mutable. However to be really consistent, more types of objects would need to be made immutable as well.
Not all types, however. For example, there'd be no point to freezing immediate objects like Fixnum because there is effectively only one instance of Fixnum corresponding to each integer value. This is why only String needs to be special-cased this way, not Fixnum and Symbol.
Strings are a special exception simply as a matter of convenience for Ruby programmers, because strings are very often used as hash keys.
Conversely, the reason that other object types are not frozen like this, which admittedly leads to inconsistent behavior, is mostly a matter of convenience for Matz & Company to not support edge cases. In practice, comparatively few people will use a container object like an array or a hash as a hash key. So if you do so, it's up to you to freeze before insertion.
Note that this is not strictly about performance, because the act of freezing a non-immediate object simply involves flipping the FL_FREEZE bit on the basic.flags bitfield that's present on every object. That's of course a cheap operation.
Also speaking of performance, note that if you are going to use string keys, and you are in a performance-critical section of code, you might want to freeze your strings before doing the insertion. If you don't, then a dup is triggered, which is a more-expensive operation.
Update #sawa pointed out that leaving your array-key simply frozen means the original array might be unexpectedly immutable outside of the key-use context, which could also be an unpleasant surprise (although otoh it would serve you right for using an array as a hash-key, really). If you therefore surmise that dup + freeze is the way out of that, then you would in fact incur possible noticeable performance cost. On the third hand, leave it unfrozen altogether, and you get the OP's original weirdness. Weirdness all around. Another reason for Matz et al to defer these edge cases to the programmer.
See this thread on the ruby-core mailing list for an explanation (freakily, it happened to be the first mail I stumbled across when I opened up the mailing list in my mail app!).
I've no idea about the first part of your question, but hHere is a practical answer for the 2nd part:
new_hash = {}
h.each_pair do |k,v|
new_hash.merge!({k.downcase => v})
end
h.replace new_hash
There's lots of permutations of this kind of code,
Hash[ h.map{|k,v| [k.downcase, v] } ]
being another (and you're probably aware of these, but sometimes it's best to take the practical route:)
You are askin 2 different questions: theoretical and practical. Lain was the first to answer, but I would like to provide what I consider a proper, lazier solution to your practical question:
Hash.new { |hsh, key| # this block get's called only if a key is absent
downcased = key.to_s.downcase
unless downcased == key # if downcasing makes a difference
hsh[key] = hsh[downcased] if hsh.has_key? downcased # define a new hash pair
end # (otherways just return nil)
}
The block used with Hash.new constructor is only invoked for those missing keys, that are actually requested. The above solution also accepts symbols.
A very old question - but if anyone else is trying to answer the "how can I get around the hash keys are freezing strings" part of the question...
A simple trick you could do to solve the String special case is:
class MutableString < String
end
s = MutableString.new("a")
h = {s => :s}
h.keys.first.upcase! # => RuntimeError: can't modify frozen String
puts h.inspect
Doesn't work unless you are creating the keys, and unless you are then careful that it doesn't cause any problems with anything that strictly requires that the class is exactly "String"
I have a Ruby array like this
q_id = [1,2,3,4,5,...,100]
I want to iterate through the array and convert into a hash like this
{
:1 => { #some hash} ,
:2 => { #another hash},
...
:100 => {#yet another hash}
}
What is the shortest and most elegant way to accomplish this?
[EDIT : the to_s.to_sym while being handy is not how I want it. Apologies for not mentioning it earlier.]
For creating a symbol, either of these work:
42.to_s.to_sym
:"#{42}"
The #inspect representation of these shows :"42" only because :42 is not a valid Symbol literal. Rest assured that the double-quotes are not part of the symbol itself.
To create a hash, there is no reason to convert the keys to symbols, however. You should simply do this:
q_id = (1..100).to_a
my_hash_indexed_by_value = {}
q_id.each{ |val| my_hash_indexed_by_value[val] = {} }
Or this:
my_hash = Hash[ *q_id.map{ |v| [v,{}] }.flatten ]
Or this:
# Every time a previously-absent key is indexed, assign and return a new hash
my_hash = Hash.new{ |h,val| h[val] = {} }
With all of these you can then index your hash directly with an integer and get a unique hash back, e.g.
my_hash[42][:foo] = "bar"
Unlike JavaScript, where every key to an object must be a string, Hashes in Ruby accept any object as the key.
To translate an integer into a symbol, use to_s.to_sym .. e.g.,:
1.to_s.to_sym
Note that a symbol is more related to a string than an integer. It may not be as useful for things like sorting anymore.
Actually "symbol numbers" aren't a thing in Ruby (try to call the to_sym method on a number). The benefit of using symbols in a hash is about performance, since they always have the same object_id (try to call object_id on strings, booleans, numbers, and symbols).
Numbers are immediate value and, like Symbol objects, they always have the same object_id.
Anyway, using the new hash syntax implies using symbols as keys, but you can always use the old good "hash rocket" syntax
awesome_hash = { 1 => "hello", 2 => "my friend" }
Read about immediate values here:
https://books.google.de/books?id=jcUbTcr5XWwC&pg=PA73&lpg=PA73&dq=immediate+values+singleton+method&source=bl&ots=fIFlAe8xjy&sig=j7WgTA1Cft0WrHwq40YdTA50wk0&hl=en&sa=X&ei=0kHSUKCVB-bW0gHRxoHQAg&redir_esc=y#v=onepage&q&f=false
If you are creating a hard-coded constant numeric symbol, there's a simpler way:
:'99'
This produces the same results as the more complex methods in other answers:
irb(main):001:0> :'99'
=> :"99"
irb(main):002:0> :"#{99}"
=> :"99"
irb(main):003:0> 99.to_s.to_sym
=> :"99"
Of course, this will not work if you're dynamically creating a symbol from a variable, in which case one of the other two approaches is required.
As already stated, :1 is not a valid symbol. Here's one way to do what you're wanting, but with the keys as strings:
Hash[a.collect{|n| [n.to_s, {}] }]
An array of the objects you want in your hash would be so much easier to use, wouldn't it? Even a hash of integers would work pretty well, wouldn't it?
u can use
1.to_s.to_sym
but this will make symbols like :"1"
You can make symbolic keys with Hash[]:
a = Hash[(1..100).map{ |x| ["#{x}".to_sym, {}] }]
Check type of hash keys:
puts a.keys.map(&:class)
=>
Symbol
...
Symbol
Symbol
I'm not entirely sure if this is possible in Ruby, but hopefully there's an easy way to do this. I want to declare a variable and later find out the name of the variable. That is, for this simple snippet:
foo = ["goo", "baz"]
How can I get the name of the array (here, "foo") back? If it is indeed possible, does this work on any variable (e.g., scalars, hashes, etc.)?
Edit: Here's what I'm basically trying to do. I'm writing a SOAP server that wraps around a class with three important variables, and the validation code is essentially this:
[foo, goo, bar].each { |param|
if param.class != Array
puts "param_name wasn't an Array. It was a/an #{param.class}"
return "Error: param_name wasn't an Array"
end
}
My question is then: Can I replace the instances of 'param_name' with foo, goo, or bar? These objects are all Arrays, so the answers I've received so far don't seem to work (with the exception of re-engineering the whole thing ala dbr's answer)
What if you turn your problem around? Instead of trying to get names from variables, get the variables from the names:
["foo", "goo", "bar"].each { |param_name|
param = eval(param_name)
if param.class != Array
puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
return "Error: #{param_name} wasn't an Array"
end
}
If there were a chance of one the variables not being defined at all (as opposed to not being an array), you would want to add "rescue nil" to the end of the "param = ..." line to keep the eval from throwing an exception...
You need to re-architect your solution. Even if you could do it (you can't), the question simply doesn't have a reasonable answer.
Imagine a get_name method.
a = 1
get_name(a)
Everyone could probably agree this should return 'a'
b = a
get_name(b)
Should it return 'b', or 'a', or an array containing both?
[b,a].each do |arg|
get_name(arg)
end
Should it return 'arg', 'b', or 'a' ?
def do_stuff( arg )
get_name(arg)
do
do_stuff(b)
Should it return 'arg', 'b', or 'a', or maybe the array of all of them? Even if it did return an array, what would the order be and how would I know how to interpret the results?
The answer to all of the questions above is "It depends on the particular thing I want at the time." I'm not sure how you could solve that problem for Ruby.
It seems you are trying to solve a problem that has a far easier solution..
Why not just store the data in a hash? If you do..
data_container = {'foo' => ['goo', 'baz']}
..it is then utterly trivial to get the 'foo' name.
That said, you've not given any context to the problem, so there may be a reason you can't do this..
[edit] After clarification, I see the issue, but I don't think this is the problem.. With [foo, bar, bla], it's equivalent like saying ['content 1', 'content 2', 'etc']. The actual variables name is (or rather, should be) utterly irrelevant. If the name of the variable is important, that is exactly why hashes exist.
The problem isn't with iterating over [foo, bar] etc, it's the fundamental problem with how the SOAP server is returing the data, and/or how you're trying to use it.
The solution, I would say, is to either make the SOAP server return hashes, or, since you know there is always going to be three elements, can you not do something like..
{"foo" => foo, "goo" => goo, "bar"=>bar}.each do |param_name, param|
if param.class != Array
puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
puts "Error: #{param_name} wasn't an Array"
end
end
OK, it DOES work in instance methods, too, and, based on your specific requirement (the one you put in the comment), you could do this:
local_variables.each do |var|
puts var if (eval(var).class != Fixnum)
end
Just replace Fixnum with your specific type checking.
I do not know of any way to get a local variable name. But, you can use the instance_variables method, this will return an array of all the instance variable names in the object.
Simple call:
object.instance_variables
or
self.instance_variables
to get an array of all instance variable names.
Building on joshmsmoore, something like this would probably do it:
# Returns the first instance variable whose value == x
# Returns nil if no name maps to the given value
def instance_variable_name_for(x)
self.instance_variables.find do |var|
x == self.instance_variable_get(var)
end
end
There's Kernel::local_variables, but I'm not sure that this will work for a method's local vars, and I don't know that you can manipulate it in such a way as to do what you wish to acheive.
Great question. I fully understand your motivation. Let me start by noting, that there are certain kinds of special objects, that, under certain circumstances, have knowledge of the variable, to which they have been assigned. These special objects are eg. Module instances, Class instances and Struct instances:
Dog = Class.new
Dog.name # Dog
The catch is, that this works only when the variable, to which the assignment is performed, is a constant. (We all know that Ruby constants are nothing more than emotionally sensitive variables.) Thus:
x = Module.new # creating an anonymous module
x.name #=> nil # the module does not know that it has been assigned to x
Animal = x # but will notice once we assign it to a constant
x.name #=> "Animal"
This behavior of objects being aware to which variables they have been assigned, is commonly called constant magic (because it is limited to constants). But this highly desirable constant magic only works for certain objects:
Rover = Dog.new
Rover.name #=> raises NoMethodError
Fortunately, I have written a gem y_support/name_magic, that takes care of this for you:
# first, gem install y_support
require 'y_support/name_magic'
class Cat
include NameMagic
end
The fact, that this only works with constants (ie. variables starting with a capital letter) is not such a big limitation. In fact, it gives you freedom to name or not to name your objects at will:
tmp = Cat.new # nameless kitty
tmp.name #=> nil
Josie = tmp # by assigning to a constant, we name the kitty Josie
tmp.name #=> :Josie
Unfortunately, this will not work with array literals, because they are internally constructed without using #new method, on which NameMagic relies. Therefore, to achieve what you want to, you will have to subclass Array:
require 'y_support/name_magic'
class MyArr < Array
include NameMagic
end
foo = MyArr.new ["goo", "baz"] # not named yet
foo.name #=> nil
Foo = foo # but assignment to a constant is noticed
foo.name #=> :Foo
# You can even list the instances
MyArr.instances #=> [["goo", "baz"]]
MyArr.instance_names #=> [:Foo]
# Get an instance by name:
MyArr.instance "Foo" #=> ["goo", "baz"]
MyArr.instance :Foo #=> ["goo", "baz"]
# Rename it:
Foo.name = "Quux"
Foo.name #=> :Quux
# Or forget the name again:
MyArr.forget :Quux
Foo.name #=> nil
# In addition, you can name the object upon creation even without assignment
u = MyArr.new [1, 2], name: :Pair
u.name #=> :Pair
v = MyArr.new [1, 2, 3], ɴ: :Trinity
v.name #=> :Trinity
I achieved the constant magic-imitating behavior by searching all the constants in all the namespaces of the current Ruby object space. This wastes a fraction of second, but since the search is performed only once, there is no performance penalty once the object figures out its name. In the future, Ruby core team has promised const_assigned hook.
You can't, you need to go back to the drawing board and re-engineer your solution.
Foo is only a location to hold a pointer to the data. The data has no knowledge of what points at it. In Smalltalk systems you could ask the VM for all pointers to an object, but that would only get you the object that contained the foo variable, not foo itself. There is no real way to reference a vaiable in Ruby. As mentioned by one answer you can stil place a tag in the data that references where it came from or such, but generally that is not a good apporach to most problems. You can use a hash to receive the values in the first place, or use a hash to pass to your loop so you know the argument name for validation purposes as in DBR's answer.
The closest thing to a real answer to you question is to use the Enumerable method each_with_index instead of each, thusly:
my_array = [foo, baz, bar]
my_array.each_with_index do |item, index|
if item.class != Array
puts "#{my_array[index]} wasn't an Array. It was a/an #{item.class}"
end
end
I removed the return statement from the block you were passing to each/each_with_index because it didn't do/mean anything. Each and each_with_index both return the array on which they were operating.
There's also something about scope in blocks worth noting here: if you've defined a variable outside of the block, it will be available within it. In other words, you could refer to foo, bar, and baz directly inside the block. The converse is not true: variables that you create for the first time inside the block will not be available outside of it.
Finally, the do/end syntax is preferred for multi-line blocks, but that's simply a matter of style, though it is universal in ruby code of any recent vintage.
What's the difference between a string and a symbol in Ruby and when should I use one over the other?
The main difference is that multiple symbols representing a single value are identical whereas this is not true with strings. For example:
irb(main):007:0> :test.object_id
=> 83618
irb(main):008:0> :test.object_id
=> 83618
irb(main):009:0> :test.object_id
=> 83618
Those are three references to the symbol :test, which are all the same object.
irb(main):010:0> "test".object_id
=> -605770378
irb(main):011:0> "test".object_id
=> -605779298
irb(main):012:0> "test".object_id
=> -605784948
Those are three references to the string "test", but are all different objects.
This means that using symbols can potentially save a good bit of memory depending on the application. It is also faster to compare symbols for equality since they are the same object, comparing identical strings is much slower since the string values need to be compared instead of just the object ids.
As far as when to use which, I usually use strings for almost everything except things like hash keys where I really want a unique identifier, not a string.
What are the differences between Symbols and Strings?
Symbols are immutable: Their value remains constant.
Multiple uses of the same symbol have the same object ID and are the same object compared to string which will be a different object with unique object ID, everytime.
You can't call any of the String methods like split on Symbols.
From Understanding Differences Between Symbols & Strings in Ruby
If you know Chinese, you can also read 理解 Ruby Symbol.
The statement:
foo = "bar"
creates a new object in memory. If we repeat the statement:
foo = "bar"
We create another object.
To understand it more clearly please try this code in IRB:
foo = "bar"
puts "string #{foo} with object id = #{foo.object_id}"
foo = "bar"
puts "string #{foo} with object id = #{foo.object_id}"
You will get output like:
string bar with object id = 70358547221180
string bar with object id = 70358548927060
which clearly shows there are two different object for the same string. Now if you use a symbol it will create one object per symbol so:
foo = :bar
puts "symbol #{foo} with object id = #{foo.object_id}"
foo = :bar
puts "symbol #{foo} with object id = #{foo.object_id}"
shows:
symbol bar with object id = 7523228
symbol bar with object id = 7523228
which means there is only one object for :bar.
Further, Symbols are immutable and you can't call any of the String methods like upcase or split on Symbols.
Comparing Symbols are faster than comparing Strings. Symbols can be thought of as constant/immutable strings that form a unique set that are effectively converted to memory pointers on the heap. This means comparing two symbols is fast because you are just comparing two integers (memory pointers).
Strings are mutable so the memory pointer to their value on the heap can change after modification. This means comparison operations are slower because duplicates can exist that are semantically equivalent.
Use a symbol when you are sure that the value will remain constant, for example use symbols for hash keys. Use a string when you want to change the value or want to use a string method on it.
An additional difference between String and Symbol is that a String has a lot more methods on it for string manipulation, while a Symbol is a relatively lean object.
Check out the documentation for the String class and the Symbol class.
Case where symbol can be disaster. Lets say you have
params.map(&:to_sym) in your rails controller .
Now here if you are converting the data provided by the user to symbol due to some reason then it could be dangerous. If the data provided by the user is too large and as we know that symbol is not a garbage collector, you might end up exhausting your server's memory which can takedown your website.
There are two main differences between String and Symbol in Ruby.
String is mutable and Symbol is not:
Because the String is mutable, it can be change in somewhere and can lead to the result is not correct.
Symbol is immutable.
String is an Object so it needs memory allocation
puts "abc".object_id # 70322858612020
puts "abc".object_id # 70322846847380
puts "abc".object_id # 70322846815460
In the other hand, Symbol will return the same object:
puts :abc.object_id # 1147868
puts :abc.object_id # 1147868
puts :abc.object_id # 1147868
So the String will take more time to use and to compare than Symbol.
Read "The Difference Between Ruby Symbols and Strings" for more information.
The main difference is that string can have value inside a variable whereas symbol not . For example:
x = "hello"
p x => "hello"
p :x => :x
A symbol is something you use to represent names and strings. You would want to use a symbol when you may have need to use a string several times as this far easier and more productive.
And just found this via google, which may offer greater detail: Here you go
Symbols and strings are completely different this post has a little insight into the differences. As to when and where to use them, there is a pretty extensive post on this subject over on has many :through.
symbol is immutable and string is mutable.
when we perform any operation on string then it create a new object and take memory. As we perform more and more operation on string means we are consuming more and more memory.
symbol is object that are immutable mean if we perform any operation then it performs changes in original object, It will not create any object, that's why it is more profitable.
for more info, you can click here