5

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;
}

6 Answers 6

6

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.

Sign up to request clarification or add additional context in comments.

1 Comment

In C and C++ static variables are created and initialized when the application first starts, not when the function containing them is run for the first time.
4

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

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

Comments

3

Scope your variable in a method and return lambda

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

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

2 Comments

I'm accepting this as it seems closest to what I've asked. Thanks!
@DavidUnric closure? As opposed to clojure the language?
3

You can use a global variable:

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

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

Comments

1

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

Comments

0

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
...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.