rubyprogramming-languages

Does ruby create a temporary variable when you type a number literal?


I am working on my own language and wondering how other language do things. When I am using irb for example and just type a number like "5" I get:

irb(main):001:0> 5
=> 5
irb(main):003:0> 5.class
=> Integer
irb(main):002:0> local_variables 
=> [:_]

But maybe GC cleans up things, so if I disable it and try:

irb(main):005:0> include GC
=> Object
irb(main):006:0> GC.disable
=> false
irb(main):007:0> 5
=> 5
irb(main):008:0> local_variables
=> [:_]

I get the same thing. So it seems that maybe it doesn't, but not sure. Basically wondering how to handle expressions in my language like: a = (4 + 5)? Create a temporary variable for 4 and one for 5 and then add and return a new object for the result, or...? Guess in the case of pure numeric literals you can optimize this out, but maybe not in other cases.


Solution

  • In the case of sufficiently-small integer literals, Ruby will not allocate an object, but instead relies on an optimization with how it represents objects. You can check for yourself by asking Ruby to generate the bytecode for your expression:

    puts RubyVM::InstructionSequence.compile(<<~RUBY).disassemble
      a = 4 + 5
    RUBY
    
    # ...
    # 0000 putobject                              4
    # 0002 putobject                              5
    # 0004 opt_plus                               <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr]
    # ...
    

    Every object in Ruby responds to #object_id, which is the unique ID that Ruby uses internally to identify objects. Looking at a few examples in the interpreter:

    Object.new.object_id    # => 20600
    [].object_id            # => 31880
    "".object_id            # => 98560
    0.object_id             # => 1
    1.object_id             # => 3
    (2 ** 30 - 1).object_id # => 2147483647
    (2 ** 31 - 1).object_id # => 231220
    

    ...we can see by example that Ruby assigns odd-valued object IDs to FixedNum objects below a certain limit, while all others have even-valued object IDs. Once the value becomes too large, it instead begins allocating the literal as an object. You can see how Ruby utilizes this in long rb_fix2int(VALUE), which gets the value of a FixNum as a C integer.