Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: Resumable functions with arguments

Tags:

ruby

I want a function that keeps local state in Ruby. Each time I call the function I want to return a result that depends both on a calling argument and on the function's stored state. Here's a simple example:

def inc_mult(factor)
  @state ||= 0   # initialize the state the first time.
  @state += 1    # adjust the internal state.
  factor * @state
end

Note that the state is initialized the first time, but subsequent calls access stored state. This is good, except that @state leaks into the surrounding context, which I don't want.

What is the most elegant way of rewriting this so that @state doesn't leak?

(Note: My actual example is much more complicated, and initializing the state is expensive.)

like image 887
Peter Avatar asked Feb 22 '10 02:02

Peter


People also ask

What are keyword arguments in Ruby?

Another thing about keyword arguments is that they are very explicit about the arguments you are missing. You can also combine keyword arguments with regular arguments. One strategy I’ve been observing on Ruby built-in methods is that new versions tend to add new, optional arguments, as keyword arguments.

Is Ruby a synchronous language?

Wrong. Just kidding, I mean Ruby is nice, but it's not magic. Because Ruby is a synchronous language and function calls only require the name of the function, Ruby will read receives_function (first_option) and immediately invoke the first_option method, before it enters receives_function method at all.

How to call a function without calling it in Ruby?

So let's dive into the other stuff. The symbol terminology is Ruby's built-in way to allow you to reference a function without calling it. By placing the symbol in the argument for receives_function, we are able to pass all the info along and actually get into the receives_function code block before executing anything.

How does the method method work in Ruby?

As a side note, googling "Ruby method method" is marginally annoying, so here is the link to the Ruby Docs to save you the time if you're interested. The method method takes an argument of a symbol and returns information about that symbol. When you pass it a symbol of another method, it will return something like this:


1 Answers

You probably want to encapsulate inc_mult into its own class, since you want to encapsulate its state separately from its containing object. This is how generators (the yield statement) work in Python and C#.

Something as simple as this would do it:

class Foo 
  state = 0 
  define_method(:[]) do |factor|
    state += 1
    factor * state
  end 
end

Philosophically, I think what you’re aiming for is incompatible with Ruby’s view of methods as messages, rather than as functions that can somewhat stand alone.

like image 164
Josh Lee Avatar answered Sep 20 '22 17:09

Josh Lee