Reputation: 5004
i want to keep the value of a variable static during recursive calls, for example if foo
is a function that takes name
as a parameter, i want to save the value of name
from the first call to foo
in a variable and the variable will retain the value in every recursive call to foo.
def run_app (name, startr)
if startr==1
constant_var=name
end
some_name = modify name
diff = compare some_name, constant_var
# recursive call
run_app some_name, 0
end
First call will be like, run_app "john", 1
I want the value of constant_var to be retained during the calls. How can I achieve that?
Upvotes: 1
Views: 2355
Reputation: 369594
First off, there's some redundancy in your code. diff
is assigned but never used. You can just get rid of it:
def run_app(name, startr)
constant_var = name if startr == 1
some_name = modify name
compare(some_name, constant_var)
# recursive call
run_app(some_name, 0)
end
The standard way of solving this would be to add an extra parameter for passing along that extra information:
def run_app(name, startr, constant_var)
some_name = modify name
compare(some_name, constant_var)
# recursive call
run_app(some_name, 0, constant_var)
end
Then you need to call the method like this:
run_app(tmp = 'john', 1, tmp)
# or
run_app('john', 2, nil)
However, this leaks a ton of internal implementation details out to the caller and places a heavy burden on them. For example, they need to know that the first and third argument need to be the same object. But only if they pass 1
as the second argument. If they pass something other than 1
, then they need to pass nil
as the third argument.
What's to stop someone from calling
run_app('john', 1, 'ringo')
# or
run_app(tmp = 'john', 2, tmp)
You can slightly improve that by using an optional parameter with a default argument:
def run_app(name, startr, constant_var = name if startr == 1)
some_name = modify name
compare(some_name, constant_var)
# recursive call
run_app(some_name, 0, constant_var)
end
Now you can call it like you want to:
run_app('john', 1)
# or
run_app('john', 2)
However, you can still call it like this:
run_app('john', 1, 'ringo')
# or
run_app(tmp = 'john', 2, tmp)
So, what we do is to move that logic into a private
helper method and give the public method the API we want:
def run_app(name, startr)
constant_var = name if startr == 1
run_app_r(name, startr, constant_var)
end
private
def run_app_r(name, startr, constant_var)
some_name = modify name
compare(some_name, constant_var)
# recursive call
run_app_r(some_name, 0, constant_var)
end
Call it like this:
run_app('john', 1)
# or
run_app('john', 2)
Of course, you can now still call
run_app_r('john', 1, 'ringo')
# or
run_app_r(tmp = 'john', 2, tmp)
But at least you now have a separate method which you can clearly document as private
, e.g. by using YARD's @private
tag or just use RDoc's :nodoc:
tag to leave it out of the docs completely.
The fact that the run_app_r
method can be called from everywhere even though it is only meant to be called inside run_app
is pretty annoying. In a language like Scala which supports nested methods you would just put the run_app_r
method inside of the run_app
method, but Ruby doesn't support nested methods, so we have to find another way: Proc
s can be nested inside methods!
def run_app(name, startr)
constant_var = name if startr == 1
(run_app_r = ->(name, startr, constant_var; some_name) {
some_name = modify name
compare(some_name, constant_var)
# recursive call
run_app_r.(some_name, 0, constant_var)
}).(name, startr, constant_var)
end
Call it like this:
run_app('john', 1)
# or
run_app('john', 2)
And since blocks are closures, we don't even need to explicitly pass constant_var
along:
def run_app(name, startr)
constant_var = name if startr == 1
(run_app_r = ->(name, startr; some_name) {
some_name = modify name
compare(some_name, constant_var)
# recursive call
run_app_r.(some_name, 0)
}).(name, startr)
end
Call it like this:
run_app('john', 1)
# or
run_app('john', 2)
But all of this is moot, because your recursion doesn't have a base case and thus will loop infinitely. Or rather, you will get a stack overflow because Ruby doesn't guarantee proper tail calls.
Upvotes: 5
Reputation: 31972
One way would be to write a wrapper to your recursive call which stores the variable somewhere before calling the actual function. Perhaps as a member variable of your class.
def run_wrapper(name, startr)
@orig_name = name
run_app (name, startr)
end
def run_app(name, startr)
p @orig_name
end
A more cleaner way might be to add a third param
def run_app(name, startr, orig_name = nil)
...
run_app("blah", startr-1, orig_name || name)
end
Upvotes: 0
Reputation: 54734
I would go with a parameter for the modified name:
def run_app (name, modified_name=name)
# do something with name
modified_name = modify(name)
# recursive call
run_app name, modified_name
end
You can then call the method with just run_app("John")
Upvotes: 0