Ruby instance method & conditional local variable

2020-04-20 21:02发布

class A
  def numbers
    [1,2,3,4]
  end

  def get_numbers(condition)
    numbers = [3,5] if condition
    numbers
  end
end

a = A.new
a.get_numbers(true) # [3,5]
a.get_numbers(false) # nil

I expect it to return [1,2,3,4] in the second case !

P.S. I am not looking for a solution(I can just have two different variable names to solve my issue), rather I am looking for an explanation for this behaviour, Does ruby creates the variable numbers during runtime itself & initializes to nil because of the if condition ?

标签: ruby
2条回答
▲ chillily
2楼-- · 2020-04-20 21:36

@sawa has the answer, but I'd recommend a little different change to the code. I'd go from:

def get_numbers(condition)
  numbers = [3,5] if condition
  numbers
end

To:

def get_numbers(condition)
  return [3,5] if condition
  numbers()
end

I like to keep it simple and have the code obvious. The assignment to the local variable accomplishes nothing and using method names without the empty parenthesis is confusing/hides that it's a method call.


An alternate way to write the code, that is entirely acceptable, is:

def get_numbers(condition)
  if condition
    return [3,5] 
  else
    numbers()
  end
end

or even:

def get_numbers(condition)
  if condition
    [3,5] 
  else
    numbers()
  end
end

Writing code is all about getting the right answer, but also about being able to return to it in six months or a year and not needing to spend hours trying to remember what you did, or worse, WHY you did it. Other people inherit our code so we need to be sensitive to the destruction we can cause in their minds when we don't write clearly, cleanly and concisely.

查看更多
贪生不怕死
3楼-- · 2020-04-20 21:40

When a token can be interpreted as either a local variable or a method call, local variable has priority. The last numbers in the method definition is interpreted as a local variable. To make it interpreted as a method call, you need to make it unambiguous.

This is probably what you intended:

def get_numbers(condition)
  return numbers = [3,5] if condition
  numbers()
end

But this is very smelly code, and it should be like this:

def get_numbers(condition)
  condition ? [3,5] : numbers
end
  • Does ruby creates [create] the variable numbers during runtime itself & [and] initializes [initialize it] to nil because of the if condition?

Yes. Whether or not the condition is satisfied, Ruby will parse everything, and if a local variable is not assigned because the condition is not satisfied, it will be initialized to nil.

查看更多
登录 后发表回答