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

S

Surgeon

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
 
S

Steve Litt


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 Litt
http://www.troubleshooters.com
(e-mail address removed)
 
J

James Edward Gray II

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... ;)
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.

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 Gray II
 
B

Bill Kelly

From: "Steve Litt said:
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.

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
 
S

Steve Litt

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... ;)


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.

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 Litt
http://www.troubleshooters.com
(e-mail address removed)
 
J

James Edward Gray II

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:
=> 123

James Edward Gray II
 
J

Johannes Friestad

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 :)

Does this make it any clearer?

johannes
 
A

Austin Ziegler

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=3D -- that's it. Consider:
=3D> #<Foo:0x2d8aea8>

Note. Thus far, there's no instance variable @bar on the Foo instance baz.
=3D> ["bar", "bar=3D"]

There's our instance methods.
=3D> #<Foo:0x2d8aea8 @bar=3D32>

Now that we've called Foo#bar=3D 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=3D.

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 :mad:bar -- you're not creating a
variable @bar, you're creating instance methods #bar and #bar=3D that
happen to work on @bar in the instance.

-austin
 
J

Johannes Friestad

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
 
A

ara.t.howard

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...ing+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
 
J

Johannes Friestad

That's where the 'can be' part comes in :)
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 :)

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
 
J

James Britt

Yohanes said:
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
 
A

ara.t.howard

That's where the 'can be' part comes in :)
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 :)

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

cheers.

-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
===============================================================================
 
S

Simon Kröger

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
 
J

Johannes Friestad

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 =3D :host
PORT =3D :port
foo1 =3D {
HOST =3D> 'localhost',
PORT =3D> 80
}

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

jf
 
J

Jim Weirich

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

My benchmark shows symbols to have a slight edge. I've attached my
benchmark at the end for review. (Benchmarks are tricky ... sometimes
you don't measure what you think you are measuring).

$ ruby string_symbol_time.rb
Strings Filling
14.080000 0.090000 14.170000 ( 14.406058)
Strings Fetching
4.320000 0.030000 4.350000 ( 4.355025)

Symbols Filling
12.300000 0.030000 12.330000 ( 12.561648)
Symbols Fetching
3.370000 0.030000 3.400000 ( 3.461109)
also, don't forget that symbols are __never__ freed.

True, but when used properly, this is rarely a concern. If they are
used as programmer names for things, then the number of symbols is
finite and not likely to grow and consume memory as the program runs.

If however, you are dynamically creating symbols by interning strings, I
would suggest you review your use of symbols and consider using strings
instead.

--
-- Jim Weirich

-------------------------------------------------------------------
#!/usr/bin/env ruby

require 'benchmark'

SIZE = 100
N = 10000

def make_str_keys
(1..SIZE).collect { |i| "key#{i}" }
end

def make_sym_keys(strs)
strs.collect { |s| s.intern }
end

def populate(keys)
result = {}
keys.each_with_index do |k, i|
result[k] = i
end
result
end

def fetch(keys, hash)
keys.each do |key| hash[key] end
end

strs = make_str_keys
syms = make_sym_keys(strs)

str_hash = populate(strs)
sym_hash = populate(syms)

puts "Strings Filling"
puts Benchmark.measure {
N.times do
populate(strs)
end
}

puts "Strings Fetching"
puts Benchmark.measure {
N.times do
fetch(strs, str_hash)
end
}

puts
puts "Symbols Filling"
puts Benchmark.measure {
N.times do
populate(syms)
end
}

puts "Symbols Fetching"
puts Benchmark.measure {
N.times do
fetch(syms, sym_hash)
end
}
 
J

Jim Weirich

James said:
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... ;)

James, you have never been out of my good graces (despite how you
describe symbols) :)
 
D

Dan Diebolt

--0-219621189-1135808323=:116
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable

How about devoting the next Ruby Quiz to coming up with the best-of-class=
examples, self paced-tutorial and documentation to settle the :symbol vs=
"string" issue? At some point you have to ask yourself are the explanati=
ons given so far to inquiring users adequate. The fact that this question=
keeps coming up must be seen as evidence that there is something lacking=
in the explanations previously given. At a minimum all the explanations =
give so far should be edited up into a FAQ entry that the experts can agr=
ee upon. Just my two cents.
6.1 What does :var mean? A colon followed by a name generates an i=
nteger(Fixnum) called a symbol which corresponds one to one with the iden=
tifier. "var".intern gives the same integer as :var, but the ``:'' form w=
ill create a local symbol if it doesn't already exist. The routines "cat=
ch", "throw", "autoload", and so on, require a string or a symbol as an a=
rgument. "method_missing", "method_added" and "singleton_method_added" (a=
nd others) require a symbol. The fact that a symbol springs into existen=
ce the first time it is referenced is sometimes used to assign unique val=
ues to constants: NORTH =3D :NORTH
SOUTH =3D :SOUTH
EAST =3D :EAST
WEST =3D :WEST =20

http://www.rubycentral.com/faq/rubyfaqall.html#s6

=09
 

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,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top