Bug #9593
closedKeyword arguments default argument assignment behaviour not consistent with optional argument
Description
Given the following code:
def var
100
end
def foo(var: var + 1)
puts "var: #{var.inspect}"
end
def bar(var = var + 1)
puts "var: #{var.inspect}"
end
foo(var: 1)
foo rescue p $!
bar(1)
bar
Ruby 2.0.0:
var: 1
var: 101
var: 1
var: 101
Ruby 2.1.1:
var: 1
#<NoMethodError: undefined method `+' for nil:NilClass>
var: 1
var: 101
What appears to be happening is that since 2.1.1, the keyword argument defines var
as a variable before evaluating the default argument. Personally, I prefer 2.0.0 behaviour, but the way 2.1.1 handles default arguments in non keyword arguments is inconsistent.
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
The behaviors in 2.0 are incorrect both.
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Status changed from Open to Closed
- % Done changed from 0 to 100
Applied in changeset r45272.
parse.y: optional arguments in rhs
- parse.y (f_arg_asgn): define optional arguments as argument
variables in the rhs default expressions.
[ruby-core:61299] [Bug #9593]
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Backport changed from 1.9.3: UNKNOWN, 2.0.0: UNKNOWN, 2.1: UNKNOWN to 1.9.3: REQUIRED, 2.0.0: REQUIRED, 2.1: REQUIRED
Updated by tenderlovemaking (Aaron Patterson) over 10 years ago
Hi,
Before r45272 this code worked:
require 'minitest/autorun'
class DefaultArg < MiniTest::Unit::TestCase
class Default
def foo; 'foo'; end
def bar foo = foo
foo
end
end
def test_default
assert_equal 'foo', Default.new.bar
end
end
Was this expected to break? Unfortunately we have real code that depends on the behavior:
but we can change it
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
Aaron Patterson wrote:
Was this expected to break?
Yes. It was a bug.
An assignment creates a variable and it hides same name method in its RHS, as you can't call foo
method inside bar
method:
def foo; 'foo'; end
def bar
foo = foo # nil
end
Unfortunately we have real code that depends on the behavior:
Sorry for the bug.
but we can change it
Always you can call the method explicitly with ()
.
Updated by tenderlovemaking (Aaron Patterson) over 10 years ago
Ok! I will fix the code in Rails. Thank you!
Updated by tenderlovemaking (Aaron Patterson) over 10 years ago
Nobu, are you sure this is a bug? This test has worked since 1.9.3, and this code was committed in 2008:
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/values/time_zone.rb#L285
It's been the behavior for at least 6 years. I don't mind changing Rails to work with this, but people who don't test with trunk may get a nasty surprise when Ruby 2.2 is released.
Edit: here's a better link: https://github.com/rails/rails/blob/15720df1808b249bae91e5600d6f0676990a7de0/activesupport/lib/active_support/values/time_zone.rb#L285
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
Yes, it's a very old bug.
Optional arguments have same semantics as assignments.
Updated by nagachika (Tomoyuki Chikanaga) over 10 years ago
Hi,
I think this change should not be backported to stable branch.
I agree about that it is a long standing bug. But it lives too long to change a behavior during stable releases.
I'm going to fill 'DONTNEED' in 'Backport' field if there's no objection.
Updated by nagachika (Tomoyuki Chikanaga) over 10 years ago
- Backport changed from 1.9.3: REQUIRED, 2.0.0: REQUIRED, 2.1: REQUIRED to 1.9.3: DONTNEED, 2.0.0: DONTNEED, 2.1: DONTNEED
No objection. I changed Backport field to DONTNEED
.
Updated by nobu (Nobuyoshi Nakada) about 10 years ago
- Has duplicate Bug #10280: Regression while evaluating default argments of a method added
Updated by hsbt (Hiroshi SHIBATA) about 10 years ago
- Related to Bug #10314: Default argument lookup fails in Ruby 2.2 for circular shadowed variable names added
Updated by nobu (Nobuyoshi Nakada) over 9 years ago
- Related to Bug #11074: Block with optional parameter of same closure variable name added