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.)
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.
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.
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.
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With