Trying to understand symbols

S

Sam Kong

Hello!

I don't fully understand symbols in Ruby even if I've read books and
postings here.

Symbols are often compared to strings like the following.

h1 = {:a => 1} #symbol. faster and immutable.
h2 = {'a' => 1}

Ok, I can understand that.
Now, is the term 'symbol' used the same meaning in the following text
(from PickAxe2 page 314)?

<snip>
When Ruby sees a name such as a in an expression, it needs to determine
if it is a local
variable reference or a call to a method with no parameters. To decide
which is the case,
Ruby uses a heuristic. As Ruby parses a source file, it keeps track of
symbols that have
been assigned to. It assumes that these symbols are variables. When it
subsequently
comes across a symbol that could be a variable or a method call, it
checks to see if
it has seen a prior assignment to that symbol. If so, it treats the
symbol as a variable;
otherwise it treats it as a method call. As a somewhat pathological
case of this, consider
the following code fragment, submitted by Clemens Hintze.
</snip>


Before I met Ruby, I regarded 'symbol' as the one in the text.
But Ruby's symbol seems to have its unique meaning and usage.

Can anybody clarify that?

Thanks.

Sam
 
J

Jacob Fugal

Symbols are often compared to strings like the following.
=20
h1 =3D {:a =3D> 1} #symbol. faster and immutable.
h2 =3D {'a' =3D> 1}
=20
Ok, I can understand that.
Now, is the term 'symbol' used the same meaning in the following text
(from PickAxe2 page 314)?
=20
<snip>
When Ruby sees a name such as a in an expression, it needs to determine
if it is a local variable reference or a call to a method with no paramet= ers. To
decide which is the case, Ruby uses a heuristic. As Ruby parses a source
file, it keeps track of symbols that have been assigned to....
</snip>

No, they are not the same. The latter is the general meaning of
symbol in a parser context. The former is a specific type of value in
Ruby.

Jacob Fugal
 
R

rcoder

You are correct to think these two usages of 'symbol' are conflicting
-- if it helps, in the text you quote from p. 314, replace the word
'symbol' with 'name'.

It's just a mis-match in terminology: in parser/compiler-speak, a
'symbol' is just a type of token, not a special kind of immutable
string like it is in Ruby.

Hope that helps,

Lennon
 
D

David A. Black

Hi --

Before I met Ruby, I regarded 'symbol' as the one in the text.
But Ruby's symbol seems to have its unique meaning and usage.
Can anybody clarify that?

A symbol object, like :x, is different from what one might generically
call a symbol. So here:

sym = :x

sym is a symbol in a generic or general sense, whereas :x is an
instance of class Symbol. When people talk about things like using
symbols as hash keys, they mean instances of Symbol -- :x and things
like that. It's common usage to call things like sym (above) symbols
too, so there's some overloading of the term.


David
 
S

Sam Kong

Thanks, rcoder!

But, what bothers me is the following case.

class Foo
def foo
puts "foo"
end
end

Foo.new.send:)foo)

In this case, :foo is not just a string-like thing.
It seems more like the one in the quoted text.

What do you think?

Sam
 
S

Sam Kong

Thanks David!
sym is a symbol in a generic or general sense, whereas :x is an
instance of class Symbol. When people talk about things like using
symbols as hash keys, they mean instances of Symbol -- :x and things
like that. It's common usage to call things like sym (above) symbols
too, so there's some overloading of the term.

Your explanation made it clear!

One more think to clear up.

f.send:)foo) #<- is :foo a symbol like an instance of Symbol or just a
generic symbol?
If :foo is not an instance of Symbol, then ':' is used for 2 kinds of
things in Ruby, right?

Thanks.

Sam
 
D

David A. Black

Hi --

Thanks, rcoder!

But, what bothers me is the following case.

class Foo
def foo
puts "foo"
end
end

Foo.new.send:)foo)

In this case, :foo is not just a string-like thing.
It seems more like the one in the quoted text.

What do you think?

The :foo in send:)foo) is just a symbol (instance of Symbol :). It
has no special status beyond that. It happens to match the name of a
method, but the symbol object has no relation to that method.

send is defined so that it can take a symbol or a string; you could
also do:

Foo.new.send("foo")

which can be handy when you need to do string interpolation to get the
name of the method.


David
 
D

Daniel Amelang

In this case, :foo is not just a string-like thing.
It seems more like the one in the quoted text.

In this case, ruby is using an instance of the Symbol class as the
search criterion for finding the method. The 'symbol' in the sense of
the compiler token never comes into play, because the compiler isn't
involved at run time (barring an 'eval' call). The compiler 'symbols'
have already been translated into their ruby internal representations
(ok, I used broad strokes here, bear with me). Send() just uses the
:foo symbol to search the ruby internals for a method with the name
'foo'. BTW, you could have used 'foo' instead of :foo.

Dan
 
J

Jay Levitt

The :foo in send:)foo) is just a symbol (instance of Symbol :). It
has no special status beyond that. It happens to match the name of a
method, but the symbol object has no relation to that method.

Really? Is that always true - a Ruby symbol is essentially a C enum
except that you can't define an int value for it?

So that would mean that Rails's use of symbols (e.g. attr_reader :foo)
is just a convention, and Rails uses the symbol-name to go look up an
Object with the same name, thus appearing to releate the Symbol to the
Object?
 
J

James Edward Gray II

So that would mean that Rails's use of symbols (e.g. attr_reader :foo)

Just to be clear, attr_reader :method_name is pure Ruby. It's not a
Rails-ism.

James Edward Gray II
 
M

Martin DeMello

Jay Levitt said:
Really? Is that always true - a Ruby symbol is essentially a C enum
except that you can't define an int value for it?

Sort of, though they're closer to lisp atoms - immutable strings stored
in a special lookup table. They are convertible to/from strings using
String#to_sym and Symbol#to_s. They do respond to object equality, if
that's what you meant -
a = 'hello';
b = 'hello';
c = a.to_sym;
d = b.to_sym
p [a, b, c, d].map {|i| i.object_id} #=> c and d are the same object
So that would mean that Rails's use of symbols (e.g. attr_reader :foo)
is just a convention, and Rails uses the symbol-name to go look up an
Object with the same name, thus appearing to releate the Symbol to the
Object?

It's a common ruby convention, but yes, attr_reader etc. are just
methods that take Symbol arguments, and could have been written to take
String args instead.

martin
 
J

Jay Levitt

It's a common ruby convention, but yes, attr_reader etc. are just
methods that take Symbol arguments, and could have been written to take
String args instead.

Thanks. I had always assumed that a symbol :foo was somehow a reference
to the var/method/whatever called foo.
 
D

Daniel Brockman

Martin DeMello said:
It's a common ruby convention, but yes, attr_reader
etc. are just methods that take Symbol arguments, and
could have been written to take String args instead.

In fact, they do take string arguments.

class Foo
attr_accessor "bar"
end

foo = Foo.new
foo.bar = 123
foo.bar #=> 123
 
D

Dave Burt

Sam Kong asked:
One more think to clear up.

f.send:)foo) #<- is :foo a symbol like an instance of Symbol or just a
generic symbol?
If :foo is not an instance of Symbol, then ':' is used for 2 kinds of
things in Ruby, right?

:foo is an instance of Symbol

% irb
irb(main):001:0> :foo.is_a? Symbol
=> true

The colon :)) prefix is Ruby for a literal Symbol, just like surrounding
something in quotes (" or ') gives a String, or slashes (/) gives a Regexp.

You can of course assign it to a variable like any other object:
x = :foo
f.send(x)

A "symbol" in context of the parser, like from your Pickaxe quote, has
nothing to do with programming Ruby, it's just used to denote a name or
identifier. See how the passage you quote starts: "When Ruby sees a name
such as a in an expression" - it's just talking about a word in your code
that looks like a variable name or a method name.

HTH,
Dave
 
S

Sam Kong

Thanks, Dave!

Dave said:
The colon :)) prefix is Ruby for a literal Symbol, just like surrounding
something in quotes (" or ') gives a String, or slashes (/) gives a Regexp.

May I think that symbols exist in Ruby becuase Ruby's strings are not
immutable?
Python, Java, and C# don't have symbols as far as I know.
Is it because their strings are immutable?

Thanks.

Sam
 
A

Austin Ziegler

Thanks, Dave!
=20

May I think that symbols exist in Ruby becuase Ruby's strings are
not immutable? Python, Java, and C# don't have symbols as far as I
know. Is it because their strings are immutable?

You may, but you might not be right. IMO, any comparison of Symbol
to something in Python, Java, and C# is (at best) misguided. Strings
in Ruby are (by default) mutable, but can be made immutable by
freezing them:

irb(main):001:0> a =3D "foo"
=3D> "foo"
irb(main):002:0> a << "bar"
=3D> "foobar"
irb(main):003:0> a.freeze
=3D> "foobar"
irb(main):004:0> a << "baz"
TypeError: can't modify frozen string
from (irb):4:in `<<'
from (irb):4

IIRC, this is what Hash does when it gets strings as keys:

irb(main):005:0> a =3D Hash[*%w(a b c d)]
=3D> {"a"=3D>"b", "c"=3D>"d"}
irb(main):006:0> a.keys.each { |k| puts "#{k} frozen? #{k.frozen?}" }
a frozen? true
c frozen? true
=3D> ["a", "c"]

Symbols are immutable, yes, but their primary feature is that they
are constant objects and strings aren't:

irb(main):016:0> %w(a a a).map {|el| el.freeze.__id__ }
=3D> [22676608, 22676596, 22676584]
irb(main):017:0> %w(a a a).map {|el| el.to_sym.__id__ }
=3D> [3086606, 3086606, 3086606]

The comparison of a symbol to a symbol is always going to be
computationally cheaper than the comparison of a string to a string.

-austin
--=20
Austin Ziegler * (e-mail address removed)
* Alternate: (e-mail address removed)
 
J

Jim Weirich

May I think that symbols exist in Ruby becuase Ruby's strings are not
immutable?
Python, Java, and C# don't have symbols as far as I know.
Is it because their strings are immutable?

Not really. Strings are used because of their content, immutable or not.
Symbols are used because they uniquely define a single object.

If you know lisp, then we can say that Ruby symbols are like Lisp atoms. If
you don't know Lisp, then learn it first, then we can say that Ruby symbols
are like Lisp atoms. ;)
 
S

Sam Kong

Hi, Jim!

Jim said:
Not really. Strings are used because of their content, immutable or not.
Symbols are used because they uniquely define a single object.

If you know lisp, then we can say that Ruby symbols are like Lisp atoms. If
you don't know Lisp, then learn it first, then we can say that Ruby symbols
are like Lisp atoms. ;)

Yeah. I've been reading 'Hackers and Painters' written by Paul Graham
who thinks Lisp is the best language.
I will check Lisp out some day.
Thanks.

Sam
 

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

No members online now.

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top