What is the difference between :foo and "foo"?


#1

Hi,

I am a Ruby newbie. I wish I didn’t post such a simple question here
but I had to.
What is the difference between :foo (a keyword) and “foo”(a string).
Can they be used interchangeably? Are they fundamentally same and is
the only difference performance?

Thanks in advance


#2

2005/12/28, Surgeon removed_email_address@domain.invalid:

Hi,

I am a Ruby newbie. I wish I didn’t post such a simple question here
but I had to.
What is the difference between :foo (a keyword) and “foo”(a string).
Can they be used interchangeably? Are they fundamentally same and is
the only difference performance?

http://onestepback.org/index.cgi/Tech/Ruby/SymbolsAreNotImmutableStrings.red


#3

On Wednesday 28 December 2005 02:32 pm, Alex K. wrote:

d
The preceding URL tells me unequivically that symbols aren’t strings,
but
really doesn’t tell me too much about what they are, other than what,
names???

I still don’t understand why it’s

attr_reader :fname, :lname

instead of

attr_reader @fname, @lname

How does attr_reader know that :fname corresponds to @fname. Seems like
magic
to me.

SteveT

Steve L.
http://www.troubleshooters.com
removed_email_address@domain.invalid


#4

On Dec 28, 2005, at 1:47 PM, Steve L. wrote:

http://onestepback.org/index.cgi/Tech/Ruby/
SymbolsAreNotImmutableStrings.re
d

The preceding URL tells me unequivically that symbols aren’t
strings, but
really doesn’t tell me too much about what they are, other than what,
names???

As one of the people guilty of saying what that article says we
shouldn’t, I better try to get back in Jim’s good graces by answering
this one… :wink:

to me.
Attributes of a class logically correspond to instance variables in
many cases, don’t you think? Ruby’s just making that assumption for
you.

When I see:

some_call @my_variable

I expect what is held inside of @my_variable to get passed to
some_call(), not the variable name itself. What you describe would
be the opposite and that would surely surprise a lot of people.

Furthermore, Symbols are commonly used to refer to method names (as
Ruby uses them for this internally). That’s really what we are doing
here, creating new methods by name, so it’s a good fit.

Hope that makes some sense.

James Edward G. II


#5

Alex K. removed_email_address@domain.invalid writes:

2005/12/28, Surgeon removed_email_address@domain.invalid:

Hi,

I am a Ruby newbie. I wish I didn’t post such a simple question here
but I had to.
What is the difference between :foo (a keyword) and “foo”(a string).
Can they be used interchangeably? Are they fundamentally same and is
the only difference performance?

http://onestepback.org/index.cgi/Tech/Ruby/SymbolsAreNotImmutableStrings.red

What a coincidence. Seems like Jim and I finally had enough of people
conflating symbols and immutable strings on the same day.

http://microjet.ath.cx/WebWiki/2005.12.27_UsingSymbolsForTheWrongReason.html

YS.


#6

On Wed, 28 Dec 2005 19:47:16 -0000, Steve L. removed_email_address@domain.invalid
wrote:

http://onestepback.org/index.cgi/Tech/Ruby/SymbolsAreNotImmutableStrings.re
d

The preceding URL tells me unequivically that symbols aren’t strings, but
really doesn’t tell me too much about what they are, other than what,
names???

I agree with Jim (obviously ;)) that describing symbols as immutable
strings isn’t ideal, but it did help me break away from the idea that
they
worked on some kind of internal voodoo. An object with a name seems a
good
way to put it - maybe ‘an object that is a name, by which it can be
referenced anywhere’.

So :foo is just the name, ‘foo’, as an object. A singleton object. Kind
of
like the literal ‘4’ - wherever you use that literal, you’ll get the
same
instance of Fixnum (incidentally, with object_id 9), whether you mean
four
loops, or four bananas, since four is four the same one will do.

to me.

You’re looking at it backwards. You give attr_reader a name (or
several).
It then takes those names, and just creates methods with each one.
There’s
no connection between the symbols, and the methods - it’s just like
passing in a string (which you can actually do instead) except that,
instead of creating a new string with the characters ‘lname’ or
whatever,
it just grabs the single symbol with that name, or makes it if it
doesn’t
already exist. It saves memory, and is better on performance in many
types
of system. The reader method accesses an instance variable, again named
from the symbol, and it gets created automatically at startup.

So the symbol just gives you the name - it’s up to you to supply the
context (like ‘an attribute reader with this name’ above).


#7

From: “Steve L.” removed_email_address@domain.invalid

to me.
If this helps, attr_reader itself isn’t magic or special Ruby syntax,
it’s just a method that defines helper-methods for you, using whatever
names you provide it. The symbols :fname, :lname above are just
interpreted by attr_reader as names of methods we are asking it to
define, and names of corresponding instance variables we want it to
access. (Note that: attr_reader “fname”, “lname” also works - it’s
less convenient to type than the symbol equivalents.)

I think there are more elegant ways to do this, but here’s one way we
could define our own attr_reader:

def my_attr_reader(*list_of_attr_names)
list_of_attr_names.each do |name|
eval <<-ENDFUNC
def #{name}
@#{name}
end
ENDFUNC
end
end

class Foo
my_attr_reader :foo, :bar
def initialize
@foo = 123
@bar = 456
end
end

f = Foo.new
puts f.foo, f.bar

the above program outputs:

123
456

So you can see my_attr_reader is just taking a list of “names”,
which we conveniently specify as symbols (but we could also
specify as strings, if we wanted.) Then my_attr_reader just
proceeds to use eval to define methods with the requested name,
accessing the corresponding instance variable. (Again, there
are probably more elegant ways to do this than using eval; it’s
just one way.)

Hope this helps,

Regards,

Bill


#8

On Wednesday 28 December 2005 03:00 pm, James Edward G. II wrote:

shouldn’t, I better try to get back in Jim’s good graces by answering

How does attr_reader know that :fname corresponds to @fname. Seems

I expect what is held inside of @my_variable to get passed to
some_call(), not the variable name itself.

Oh, I get it!!!

In see itwould be some_call(&@my_variable), and in ruby it’s
some_call(:my_variable). One thing – why not some_call(:@my_variable)?

What you describe would
be the opposite and that would surely surprise a lot of people.

Furthermore, Symbols are commonly used to refer to method names (as
Ruby uses them for this internally). That’s really what we are doing
here, creating new methods by name, so it’s a good fit.

Ah ha! That’s why I need to pass callback routines entry and exit that
occur
in object cb, like this:

walker = Walker.new(node, cb.method(:entry), cb.method(:exit))

SteveT

Steve L.
http://www.troubleshooters.com
removed_email_address@domain.invalid


#9

On Dec 28, 2005, at 2:35 PM, Steve L. wrote:

One thing – why not some_call(:@my_variable)?

This is a fair question I’ve asked myself once or twice. Ruby seems
to change it’s mind on this sometimes too:

class MyClass
def initialize( var )
@var = var
end
attr_reader :var # I guess we’re talking about the method here
(no @)

def fetch( name )
instance_variable_get("@#{name}") # but we need the @ now
end
end
=> nil

ex = MyClass.new(123)
=> #<MyClass:0x32565c @var=123>

ex.var
=> 123

ex.fetch(:var)
=> 123

James Edward G. II


#10

attr_reader :fname, :lname (attr_reader “fname”, “lname” works too)
knows how to map the names because that’s what an attribute is: A
read-only attribute ‘foo’ will have a getter method named ‘foo’ and an
instance variable ‘@foo’. It’s a common enough convention, used in
other languages as well. (In Java, it would be a method ‘getFoo()’ and
an instance variable ‘foo’.)

The difference between symbols and strings:

A string is a sequence of characters. You can append to a string,
parse it, split it, iterate over characters or lines and so forth. Two
strings containing the same character sequence (say “abc” and “abc”)
are equal, but not necessarily the same object.
Strings can be basically any character or byte sequence, like the
contents of a text or binary file. Strings are local and are garbage
collected when they are no longer referred to, like other objects.

A symbol is atomic, immutable and unique: It cannot be parsed or
modified, and all references to a symbol with a given name (say :abc)
refers to the same object.
Symbols tend to be short, simple names, like a single word with no
whitespace. Symbols are global, and hang around quite a bit longer
than strings normally do, often until the end of the program.

Symbols are (or can be) quicker for hash lookup, since it is
sufficient to compare object identity to find whether two symbols are
the same, while strings must be compared character by character. You
are unlikely to notice the difference unless your program uses hashes
heavily.

So they are not fundamentally the same. But there are a some cases
where they can be used interchangeably, like naming an attribute or as
hash key.

Reasons for using symbols instead of strings are mostly based on
convention. Personally, I use them basically because I save a
keystroke in typing them :slight_smile:

Does this make it any clearer?

johannes


#11

On Wed, 28 Dec 2005 20:00:13 -0000, James Edward G. II
removed_email_address@domain.invalid wrote:

really doesn’t tell me too much about what they are, other than what,
names???

As one of the people guilty of saying what that article says we
shouldn’t, I better try to get back in Jim’s good graces by answering
this one… :wink:

I still think it’s a useful description, at least for those of us coming
from Java. In fact it was reading one of your ‘priors’ that set me on
the
road to understanding a bit more - I couldn’t get away from the internal
connotations of the word ‘Symbol’ until I read that.

I still really think of symbols as an immutable representation of a
string. Although it’s not entirely accurate it suits me I think. I am
liking the Object with name thing the more I think about it. Or ‘a name
referenced by name’. Or whatever. :slight_smile:


#12

On 28/12/05, Steve L. removed_email_address@domain.invalid wrote:

Oh, I get it!!!
In see itwould be some_call(&@my_variable), and in ruby it’s
some_call(:my_variable). One thing – why not some_call(:@my_variable)?

No.

There is nothing even remotely close in C, C++, or Java.

In Ruby, it’s not some_call(:my_variable), it’s some_call(:my_name).

When you do:

attr_accessor :my_name

You do NOT get a @my_name variable. You get two methods: Foo#my_name
and Foo#my_name= – that’s it. Consider:

class Foo
attr_accessor :bar
end
=> nil

baz = Foo.new
=> #Foo:0x2d8aea8

Note. Thus far, there’s no instance variable @bar on the Foo instance
baz.

Foo.instance_methods(false)
=> [“bar”, “bar=”]

There’s our instance methods.

baz.bar = 32
=> 32

baz
=> #<Foo:0x2d8aea8 @bar=32>

Now that we’ve called Foo#bar= on the baz instance of Foo class, baz
finally has a @bar instance variable. But not a moment before, unless
we instantiate such an instance variable prior to the call of
Foo#bar=.

So :bar is a name (Symbol) used to refer to the name :bar. It is used
by attr_accessor to create two methods that also operate on a
like-named instance variable. But :bar doesn’t refer to a variable,
which is precisely why it isn’t :@bar – you’re not creating a
variable @bar, you’re creating instance methods #bar and #bar= that
happen to work on @bar in the instance.

-austin


#13

On Dec 28, 2005, at 2:51 PM, Austin Z. wrote:

=> nil

baz.bar = 32
=> 32

baz
=> #<Foo:0x2d8aea8 @bar=32>

Now that we’ve called Foo#bar= on the baz instance of Foo class, baz
finally has a @bar instance variable. But not a moment before, unless
we instantiate such an instance variable prior to the call of
Foo#bar=.

That’s what I suspected as shown in the comments of my last example,
but Austin explains it much better. Learn something new all the
time… :slight_smile:

James Edward G. II


#14

Depends on the call.
In the case of attr_, it’s because you’re naming the attribute, not
the methods or the variable. The convention (and the code behind
attr_
) will do the expansion.
In instance_variable_get(…), you are explicitly looking for a
variable, and naturally supply the variable name.
In both cases, the symbol is just a name. What we are naming depends
on the context.

jf


#15

On Thu, 29 Dec 2005, Johannes F. wrote:

Symbols are (or can be) quicker for hash lookup, since it is sufficient to
compare object identity to find whether two symbols are the same, while
strings must be compared character by character. You are unlikely to notice
the difference unless your program uses hashes heavily.

i see this claim all the time but never data supporting it, all my test
programs have shown the opposite to be true. see

http://groups.google.com/group/comp.lang.ruby/browse_frm/thread/c881186317ef8d33/e20e6e93c99b9924?q=symbol+string+hash+speed+howard&rnum=1#e20e6e93c99b9924

for some sample code.

running that sample code with the latest ruby (1.8.4) shows the gap has
narrowed, but strings are still beating symbols on my box:


- Symbol:
   max: "0.0019838809967041"
   avg: "0.0000033428150346"
   min: "0.0000019073486328"
  • String:
    max: “0.0019280910491943”
    avg: “0.0000037288846215”
    min: “0.0000019073486328”

also, don’t forget that symbols are never freed.

this is a severe memory leak:

loop{ Time::now.to_f.to_s.intern }

this is not

loop{ Time::now.to_f.to_s }

strings certainly play nicer with yaml as well.

regards.

-a

===============================================================================
| ara [dot] t [dot] howard [at] noaa [dot] gov
| all happiness comes from the desire for others to be happy. all misery
| comes from the desire for oneself to be happy.
| – bodhicaryavatara

a.rb


#16

That’s where the ‘can be’ part comes in :slight_smile:
The point is that symbols support quicker lookup by their nature.
Whether they are quicker in practice will depend on the
implementation. From the timings you give, it looks like symbol lookup
is implemented by converting the symbol to a string and doing string
lookup. Which is obviously not quicker :slight_smile:

My data were from a Common Lisp implementation, where symbols were
quicker in practice as well.
Sorry, didn’t know about the Ruby implementation. Thanks for the info.

jf


#17

Yohanes S. wrote:

Can they be used interchangeably? Are they fundamentally same and is
the only difference performance?

http://onestepback.org/index.cgi/Tech/Ruby/SymbolsAreNotImmutableStrings.red

What a coincidence. Seems like Jim and I finally had enough of people
conflating symbols and immutable strings on the same day.

http://microjet.ath.cx/WebWiki/2005.12.27_UsingSymbolsForTheWrongReason.html

Question: Would using a constant be equally suitable for expressing
intention, and (possibly) less error-prone?

Assume ConstUtils.next_value

ensures unique values

HOST = ConstUtils.next_value
PORT = ConstUtils.next_value

foo1 = {
HOST => ‘localhost’,
PORT => 80
}

A downside to using symbols as constants is that this will not raise any
exceptions:

foo1 = {
:hots => ‘localhost’,
:prt => 80
}

But a typo in a constant will.

James

http://www.ruby-doc.org - Ruby Help & Documentation
http://www.artima.com/rubycs/ - Ruby Code & Style: Writers wanted
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://www.jamesbritt.com - Playing with Better Toys
http://www.30secondrule.com - Building Better Tools


#18

On Thu, 29 Dec 2005, Johannes F. wrote:

That’s where the ‘can be’ part comes in :slight_smile:
The point is that symbols support quicker lookup by their nature.
Whether they are quicker in practice will depend on the
implementation. From the timings you give, it looks like symbol lookup
is implemented by converting the symbol to a string and doing string
lookup. Which is obviously not quicker :slight_smile:

i never consider that as an impl - i bet your right though… time for
me to
read the source.

cheers.

-a


#19

I’m all with you, you may even use

HOST = :host
PORT = :port

instead of ConstUtils.next_value, but anybody else will tell you
to use modul tests to find your errors instead of letting the
interpreter find them.

(Agreed, sharp knifes are better than dull ones, but even if all
you need is a spoon?)

cheers

Simon


#20

Question: Would using a constant be equally suitable for expressing
intention, and (possibly) less error-prone?

I agree. But there’s no law against using both:

HOST = :host
PORT = :port
foo1 = {
HOST => ‘localhost’,
PORT => 80
}

which is equally safe, simpler to read, doesn’t need the ConstUtil,
and automagically gives a constant with a readable string value.

jf