Search code examples
rubystructclass-instance-variables

How to define a class instance variable in Ruby Struct subclass?


How can I define a variable that has shared access by instance methods of a Struct?

I can use a global variable $tmp like this:

Triple = Struct.new :x, :y, :z do 
  def mul s 
    $tmp.x = x * s
    $tmp.y = y * s
    $tmp.z = z * s    
    return $tmp     
  end   
end

$tmp = Triple[0.0, 0.0, 0.0]

one = Triple[1.0, 1.0, 1.0]
puts $tmp
puts one
one.mul 7.5
puts $tmp
puts one

:and:

$ /opt/src/ruby-3.3.5/bin/ruby --yjit -W0 example.rb
#<struct Triple x=0.0, y=0.0, z=0.0>
#<struct Triple x=1.0, y=1.0, z=1.0>
#<struct Triple x=7.5, y=7.5, z=7.5>
#<struct Triple x=1.0, y=1.0, z=1.0>

But I only want the variable to be accessible within Struct Triple, something like this:

Triple = Struct.new :x, :y, :z do 

  @tmp = Triple[0.0, 0.0, 0.0]

  def mul s 
    @tmp.x = x * s
    @tmp.y = y * s
    @tmp.z = z * s    
    return @tmp     
  end   
end

:but:

$ /opt/src/ruby-3.3.5/bin/ruby --yjit -W0 example.rb
example.rb:4:in `block in <main>': uninitialized constant Triple (NameError)

  @tmp = Triple[0.0, 0.0, 0.0]
         ^^^^^^

Solution

  • While I am very unclear on your intentions here, you can accomplish your goal by assigning an instance variable inside a class instance method definition

    Triple = Struct.new :x, :y, :z do  
      def self.tmp 
        @tmp ||= new(0,0,0)
      end
    
      def tmp = self.class.tmp
      
      def mul s 
        tmp.x = x * s
        tmp.y = y * s
        tmp.z = z * s    
        tmp     
      end   
    end
    

    This will result in

    one = Triple[1.0, 1.0, 1.0]
    #=> #<struct Triple x=1.0, y=1.0, z=1.0>
    one.tmp
    #=> #<struct Triple x=0.0, y=0.0, z=0.0>
    one.mul 7.5
    #=> #<struct Triple x=7.5, y=7.5, z=7.5>
    one
    #=> #<struct Triple x=1.0, y=1.0, z=1.0>
    one.tmp
    #=> #<struct Triple x=7.5, y=7.5, z=7.5>
    Triple.tmp
    #=> #<struct Triple x=7.5, y=7.5, z=7.5>