'What is use of ||= begin....end block in Ruby?

What is the difference between these snippets?

def config
  @config ||= begin
                if config_exists?
                  @config = return some value
                else
                  {}
                end
              end
end
 
def config
  @config ||= method
end

def method
  if config_exists?
    return some value
  else
    {}
  end
end

I'm confused with the "begin ... end" block. Does it make any difference in the output? If not, then what is the use of the begin ... end block here?



Solution 1:[1]

In your case, you can even omit the begin ... end block:

@config ||=
  if config_exists?  
    return_some_value
  else
    {}
  end

or, using the ternary if:

@config ||= config_exists? ? return_some_value : {}

Does it make any difference in output?

It could make a difference, because unlike def ... end, an begin ... end block doesn't create a new variable scope.

Here's a contrived example:

def foo
  a = 456  # doesn't affect the other a
end

a = 123
b = foo

p a: a, b: b #=> {:a=>123, :b=>456}

Versus:

a = 123
b = begin
  a = 456  # overwrites a
end

p a: a, b: b #=> {:a=>456, :b=>456}

Solution 2:[2]

Using ||= begin...end allows you to memoize the result of whatever is run in the begin...end. This is useful for caching the result of resource-intensive computation.

Solution 3:[3]

The only thing that will happen differently is if an exception is raised. For instance, let's say there is a problem in the config_exists? method call. If it raises an exception in the first example your @config var will be set to {}. In the second example if the same thing happens your program will crash.

As a side note, there is no need for the return keyword here. In fact the example should read as follows. This is assuming that I understand the intent.

def config
  @config ||= 
    begin
      if config_exists?    
        some_value
      else
        {}
      end
    rescue
      {}
    end
end

and

def config
  @config ||= method
end

def method
  if config_exists?
    some_value
  else
    {}
  end
end

Both examples are exactly the same, except if an exception is raised @config will still be set to = some_value in the first example.

Also, it should be noted that nothing will happen if @config already has a value. The ||= operators is the same as:

@config = some_value if @config.nil?

Only set the variable to this value if it is currently nil.

Hope this is helpful and that I am understanding your question correctly.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Stefan
Solution 2 shanecav
Solution 3