New to programming and to Ruby, and I hope this question about symbols is in line. I understand that symbols in Ruby (e.g., :book
, :price
) are useful particularly as hash keys, and for all-around doing a lightweight, specific subset of the things that strings can do.
However, I am confused about symbols in one respect. Specifically, when they're used in the attr_accessor
types of methods, it appears that they are behaving more like a variable. E.g., attr_reader :book, :price
.
If true that they are variables in that usage, this is a bit puzzling because they are not typically listed among variable types (like the $global, @instance, local, @@class, and sometimes, CONSTANT, variable types) when variables types are described.
And if symbols are variables when used this way, what scope should be expected of them? Or are they still somehow lightweight strings in this context as well? (Or perhaps in some broader way, do symbols, strings, and variables all share a fundamental duck-like nature?) Thank you in advance for your insights and advice.
Ruby's
attr_accessor
,attr_reader
, andattr_writer
are just shorthand ways of avoiding writing a bit of repetitive code. The following question expands on how these work: Why use Ruby's attr_accessor, attr_reader and attr_writer?Instead of thinking of
attr_reader :book
as a variable, just think of it as a name of an attribute that is specified using a symbol.They aren't variables because they don't hold values, they are immutable. The thing is the value itself. It's similar to numbers. You can't set the value of
1
.1 = 2
doesn't work.Symbols used in accessor methods are not variables. They are just representing the name of a variable. Variables hold some reference, so you cannot use a variable itself in defining accessor methods. For example, suppose you wanted to define an accessor method for the variable
@foo
in a context where its value is"bar"
. What would happen if Ruby's syntax were to be like this:This would be no different from writing:
where you have no access to the name
@foo
that you are interested in. Therefore, such constructions have to be designed to refer to variable names at a meta level. Symbol is used for this reason. They are not variables themselves. They represent the name of a variable.And the variable relevant to accessor methods are instance variables.
Symbols are not variables, but a type of literal value, like numerals and quoted strings. Significantly, symbols are used to represent variables and other named values in the Ruby runtime. So when the Ruby interpreter sees the name
foo
used as a variable or method name, what it looks up in the Hash of runtime values is the symbol:foo
, not the string"foo"
. This was, in fact, the original use of the term "symbol" in programming language terminology; variables, functions, constants, methods, and so on are said to be stored in the compiler or interpreter's "symbol table".Pretty much any time you're passing around the name of something in Ruby, you're going to use a symbol. If you use
method_missing
as a catch-all to implement arbitrary methods on your object class, a symbol is what it receives as an argument telling it the name of the method that was actually called. If you inspect an object with.methods
or.instance_variables
, what you get back is an array of symbols. And so on.(Answer to your comment)
dog = 'dog'
orString.new("dog")
After dog = String.new, the field class of instance dog points to class String.
With
class << dog
ordef dog.bark
, Ruby creates an anonymous class, the field class of instance dog now points to this anonymous class, and from there to String. Methods defined in this context with def or define_method go into the methods table of the anonymous class.Ruby 1.9.2 has introduced Object#singleton_class. [The Pickaxe] Returns the singleton class of obj, creating one if necessary. (I add) It is equivalent to
class << self; self end
.The Ruby Programming Language (O'Reiily) simply says : to open the eigenclass [singleton class] of the object o, use class << o.
So I don't know how to read it loud. I have read that some would prefer
o >> class
. It's only recently that I have found how to figure out what this strange expression means. I pronounce : go from o to it's anonymous class.The same is true for a class. With
class MyClass
, MyClass, as instance of Class, is an object with a pointer to its class Class. Withdef MyClass.some_method
orclass << MyClass
, Ruby creates an anonymous class which is inserted between MyClass and Class, and class methods go into it.Yes for "from class/object" to anonymous singleton class/eigenclass/metaclass. But we don't instantiate self. Self (in Smaltalk, this in C++/Java) is kind of a reserved word which designate the receiver of the message.
dog.bark
: in OO language we say that the message bark in sent to object dog. Inside the methodbark
, self will be set to dog, so that we can reference dog. This is more obvious withsome_method must be able to reference the receiver in a generic way, is it o1 or o2, this is what self is for.
To address your "If true that they are variables" and "scope" questions, it would have been simpler to answer that accessor symbols have nothing to do with instance variables, even if it sounds iconoclastic. They don't point to instance variables. Accessors only define getter and setter methods. Under Object#instance_variables, the Pickaxe(*) says : Note that simply defining an accessor does not create the corresponding instance variable.
In Ruby, a variable does not exist until you assign a value to it. The following code demonstrates this.
Output :
1) empty array : accessors have not defined instance variables
2) asking for instance variable @name answers nil : it does not exist
3) assigning a value has created the instance variable.
Note that
name =
is a syntactic sugar for using the setter as an ordinary method with a parameter :obj.name=('xyz')
4) the getter method
name
answers the value of @name5) the getter method
book
answers nil because the instance variable @book does not exist. Defining an accessorattr_reader :book
has not defined the corresponding instance variable6) the getter method
book
answers the value assigned ininitialize
, called bynew
on line 21. The instance variable @book has been created by@book = p_book
line 26) I have always believed that accessors accept only symbols. I discover that a variable is possible, but of limited interest.
7) the setter method
title=
has created @title. This also shows that instance variables belong to a single object. We often believe that they belong to all instances of the class, as in other languages. In this case, @name belongs only to the object created on line 6.8) the getter method
title
answers the value of @titleOutput :
9) of course there is a tight correlation between an accessor symbol and the corresponding instance variable, because, behind the scene, Ruby creates methods which reference an instance variable of the same name. You could define your own getter and cheat.
Note that besides class variables (@@var, some dislike them as ugly as global variables), classes can also have instance variables. I call them class instance variables :).
class MyClass
: Ruby allocates a new instance of class Class, defines a constant MyClass, and assigns the new instance to that constant. Thus MyClass is an ordinary object (instance of Class) and as such can have instance variables.Output :
More on singleton methods here : What does def `self.function` name mean?
(*) http://pragprog.com/book/ruby3/programming-ruby-1-9