conradkleinespel
conradkleinespel

Reputation: 6987

Static variables in ruby, like in C functions

Is there any such thing as static variables in Ruby that would behave like they do in C functions?

Here's a quick example of what I mean. It prints "6\n7\n" to the console.

#include <stdio.h>

int test() {
        static int a = 5;
        a++;
        return a;
}

int main() {

        printf("%d\n", test());
        printf("%d\n", test());

        return 0;
}

Upvotes: 5

Views: 2576

Answers (6)

ichigolas
ichigolas

Reputation: 7725

What I understand about this C code is that the static variable is initialized with a value (5 in this case), and its value is persisted across function calls.

In Ruby and languages with the same level of abstraction, this same thing is typically achieved either by using a variable that sits outside the scope of the function or by using an object to hold that variable.

def test()
  @a ||= 5 # If not set, set it. We need to use an instance variable to persist the variable across calls.
  @a += 1 # sum 1 and return it's value
end

def main()
  puts test
  puts test
  0
end

Ruby's quirk is that you can use instance variables even outside of a class definition.

Upvotes: 6

cesartalves
cesartalves

Reputation: 1585

Use a variable in the singleton class (The static class itself)

class Single
  def self.counter
    if @count  
      @count+=1
    else
      @count = 5
    end
  end
end

In ruby, any class is an object which has only one instance. Therefore, you can create an instance variable on the class, and it will work as a "static" method ;)

Output:

  ruby 2.5.5p157 (2019-03-15 revision 67260) [x86_64-linux]

=> :counter
   Single.counter
=> 5
   Single.counter
=> 6
   Single.counter
=> 7

To get this behaviour on the main scope, you can do:

module Countable
  def counter
    if @count  
      @count+=1
    else
      @count = 5
    end
  end
end

=> :counter
   self.class.prepend Countable # this "adds" the method to the main object
=> Object
   counter
=> 5
   counter
=> 6
   counter
=> 7

Upvotes: 1

sawa
sawa

Reputation: 168101

I think a standard way to do this is to use Fiber.

f = Fiber.new do
  a = 5
  loop{Fiber.yield a += 1}
end

puts f.resume # => 6
puts f.resume # => 7
...

Upvotes: 0

SwiftMango
SwiftMango

Reputation: 15284

Scope your variable in a method and return lambda

def counter
  count = 0
  lambda{count = count+1}
end

test = counter
test[]
#=>1
test[]
#=>2

Upvotes: 3

Jorge Israel Pe&#241;a
Jorge Israel Pe&#241;a

Reputation: 38586

Similar to nicooga's answer but more self-contained:

def some_method
  @var ||= 0
  @var += 1
  puts @var
end

Upvotes: 4

Guilherme Bernal
Guilherme Bernal

Reputation: 8293

You can use a global variable:

$a = 5
def test
  $a += 1
end

p test #=> 6
p test #=> 7

Upvotes: 3

Related Questions