I want a way to exit a begin/end block while still assigning the variable that its result is assigned to.
def foo
@foo ||= begin
puts "running"
return "leaving early" if true # would be some sort of calculation
# Other calculations
end
end
What I hope to happen
> foo
running
=> leaving early
> foo
=> leaving early
What actually happens
> foo
running
=> leaving early
> foo
running
=> leaving early
The code doesn't work because return
exits the entire method without setting @foo
. Using break
or next
only work in loops. Does anything work within a begin block the way I'm thinking?
Current ways I can do it but was hoping to avoid:
There seem to be a lot of related questions about breaking out of blocks but I couldn't find one that answers this specific version (maybe because it's not possible).
I think you're going to save yourself a whole heck of a lot of strife if you just put all that logic into its own method:
def foo
@foo ||= compute_foo
end
def compute_foo
puts "running"
return "leaving early" if true # would be some sort of calculation
# Other calculations
end
This decouples the computation from the memoization, making it easier to test and reason about, and it's a fairly common design pattern in Ruby and other languages.
Of course, there are ways of doing what you're asking. The most obvious solution being an immediately-invoked anonymous proc:
def foo
@foo ||= (proc do
puts "running"
next "leaving early" if true # would be some sort of calculation
# Other calculations
end)[] # or .call or .()
end
But you certainly wouldn't be doing yourself or any future maintainers of this code any favors.