1

A string is a primitive type; whenever you call the string, it has a new object id. A symbol is a referenced type; whenever you create a symbol, you create a pointer, which points to the value.

I stored symbols in variables:

var1 = :foo
var1.object_id # => 2598748
:foo.object_id # => 2598748

var2 = :foo
var2.object_id # => 2598748

var2 = "hello"
var2.object_id # => 70131755422100

How is it possible that I create a second variable var2, and it has the same object id as var1? I create a second element. Does it mean that variables are also pointers?

Both variables point to the symbol :foo. The symbol :foo is stored just once, right?

Two variables are created, so they should be in the memory, and they cannot be in the same place because they have different names. var1 and var2 need to be stored, so that I can call them later. I don't get how I can call them if they have the same object id. If someone can help me to understand this, I'd be thankful.

sawa
  • 165,429
  • 45
  • 277
  • 381
AlbertMunichMar
  • 1,680
  • 5
  • 25
  • 49
  • 5
    The `object_id` is for the object held by the variable. Variables are not objects, so they don't have id's. – Cary Swoveland Oct 05 '18 at 02:48
  • why I am able then to do var.object_id? – AlbertMunichMar Oct 05 '18 at 03:00
  • 1
    `var = 7; var.object_id #=> 15; 7.object_id => 15`. – Cary Swoveland Oct 05 '18 at 03:22
  • Note that [there are no primitive types in Ruby](https://stackoverflow.com/questions/18790442/are-there-primitive-types-in-ruby), and note that, as opposed to e.g. Python, Ruby strings are _mutable_ (e.g. `foo = "hello"; puts foo.object_id; foo << ", world!"; puts foo.object_id; puts foo`). – Amadan Oct 05 '18 at 06:49
  • `var1.object_id` sends the message `object_id` to the _object_ referenced by `var1`. It might be more obvious if you look at `var1.to_s` – it returns `"foo"` instead of `"var1"`. That's because you are talking to the object, not to the variable. – Stefan Oct 05 '18 at 08:34

1 Answers1

2

Ruby variables are references to objects, so when you send a method to a variable, the object it references is the context in which it is evaluated. It's probably more clear to look at the first image in the top rated answer (below the accepted answer) here.

So, to figure out what's going on, let's dig into the documentation a bit and see what happens with your code snippet.

Ruby's Symbol class documentation: https://ruby-doc.org/core-2.5.0/Symbol.html

Symbol objects represent names and some strings inside the Ruby interpreter. They are generated using the :name and :"string" literals syntax, and by the various to_sym methods. The same Symbol object will be created for a given name or string for the duration of a program's execution, regardless of the context or meaning of that name. Thus if Fred is a constant in one context, a method in another, and a class in a third, the Symbol :Fred will be the same object in all three contexts.

Ruby's Object#object_id documentation: https://ruby-doc.org/core-2.5.1/Object.html#method-i-object_id

Returns an integer identifier for obj.

The same number will be returned on all calls to object_id for a given object, and no two active objects will share an id.

So here's what's happening step-by-step:

# We create two variables that refer to the same object, :foo
var1 = :foo
var2 = :foo

var1.object_id = 2598748
var2.object_id = 2598748
# Evaluated as:
# var1.object_id => :foo.object_id => 2598748
# var2.object_id => :foo.object_id => 2598748

As discussed in the first link above, Ruby is pass-by-value, but every value is an Object, so your variables both evaluate to the same value. Since every symbol made of the same string ("foo" in this case) refers to the same object, and Object#object_id always returns the same id for the same object, you get the same id back.

Community
  • 1
  • 1
David Bodow
  • 688
  • 5
  • 15
  • 2
    For the record, I disagree with the top answer there - "pass by value" and "pass by reference" both refer to C++ (and older) behaviours where "pass by value" clones the value, and "pass by reference" allows the variable itself to be modified. While technically "pass-by-value-where-value-is-reference" is correct, it is clumsy to say - and just "pass by value" is misleading (it's what PHP's doing, which is _not_ what Ruby and Python do). Thus it is better to use the newer terms "pass-reference-by-value", "pass-by-sharing", "pass-by-object-reference" that explicitly differentiate it. – Amadan Oct 05 '18 at 07:02