Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Ruby handle assignment semantically?

In Ruby, we assign values to objects with the = operator.

Combine this with implicit typing and we frequently get situations like this:

myVar= :asymbol

The above line both creates a new symbol object, and binds the object to the variable name myVar.

Semantically, how is this done?

I have had it hammered into my head that the = operator is not magic syntax built into the interpreter, but is actually just syntactic sugar for the object.=(value) method.

With this in mind, my best guess is that when the interpreter sees we are trying to assign a value to an undefined variable name, it first creates a new object of some special type, like undefined or null or something, and then passes the := message to that object with the payload being the value we are trying to assign.

However, calling .class on an un-instantiated object just throws an exception because Ruby thinks we're trying to call a method (whose name is the name of the variable that you're trying to bring into existence) on self

> obj.class
    > NameError: undefined variable or method 'obj' for main:Object

So, as far as I can tell, I have no way of figuring this out experimentally.


Side note:

In the case of symbol assignment, I believe that the value assigned ( A.K.A. the value returned by the instantiated object's object_id method, A.K.A. the value of the unsigned long VALUE variable on the C level) is a number that represents an offset in a table somewhere (I believe this is how Ruby achieves 'immediate value' for symbol objects).

In other cases, the value may be a direct encoding of the object itself, or a value that is meant to be cast to a pointer in reference to a struct.

Regardless, the way that Ruby represents the object and whether we end up assigning a reference or the object itself is not what I am asking about here.

Additional question:

What class is the = method inherited from? I can't find it in the spec for Object or BasicObject.

like image 696
Luke Avatar asked Apr 20 '15 19:04

Luke


1 Answers

Variables are, in a technical sense, just pointers to objects. There's nothing remarkable about that, but a simple variable assignment to an existing object does not involve any method calls or messages being sent.

Remember variables are just there so that programmers can refer to objects by name instead of by some kind of internal identifier or memory location. So there's a bit of "magic" here, = is special when making an assignment as there's rules for what you can do on the left and right side of it.

The only way you can send messages to something, that is make method calls, is if you've defined it in a way the compiler understands. x = 1 is sufficient, it means x refers to the Fixnum in question.

Note that the Ruby interpreter will need to determine if x refers to a variable or method call, as x= may be a method that's defined on the object context in which this is evaluated.

For example:

class Example
  def x=(value)
    @x = value
  end

  def test
    # Equivalent to send(:x=, 1) because x= is a method
    x = 1

    # Is a variable definition because y= is not a method
    y = 2

    # Is always a method call because self is referenced.
    self.x = 3
  end
end

# Is a variable definition because x= is not defined in this context
x = 4

If there's no x= method for your object, x is automatically presumed to be a variable.

You can't have a := message because that would imply you can replace one object with another, something that's not allowed. Once an object is created, it cannot magically change type. For that you need to create a new instance of a different object. Variables only appear to change types, but in fact, they just end up pointing to different objects.

So in short, there's no := method call, but there may be special methods like :x= that work in very specific cases.

like image 200
tadman Avatar answered Oct 14 '22 04:10

tadman