Project

General

Profile

Actions

Bug #9593

closed

Keyword arguments default argument assignment behaviour not consistent with optional argument

Added by chendo (Jack Chen) almost 11 years ago. Updated over 10 years ago.

Status:
Closed
Target version:
[ruby-core:61299]

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.


Related issues 3 (0 open3 closed)

Related to Ruby master - Bug #10314: Default argument lookup fails in Ruby 2.2 for circular shadowed variable namesClosednobu (Nobuyoshi Nakada)Actions
Related to Ruby master - Bug #11074: Block with optional parameter of same closure variable nameRejected04/18/2015Actions
Has duplicate Ruby master - Bug #10280: Regression while evaluating default argments of a methodRejected09/22/2014Actions

Updated by nobu (Nobuyoshi Nakada) almost 11 years ago

The behaviors in 2.0 are incorrect both.

Updated by nobu (Nobuyoshi Nakada) almost 11 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) almost 11 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) almost 11 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:

https://github.com/rails/rails/blob/81d08abcccf2ef1b0ea6e98daf00f6ca375f3d8a/activerecord/lib/active_record/associations/has_many_association.rb#L74

but we can change it

Updated by nobu (Nobuyoshi Nakada) almost 11 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:

https://github.com/rails/rails/blob/81d08abcccf2ef1b0ea6e98daf00f6ca375f3d8a/activerecord/lib/active_record/associations/has_many_association.rb#L74

Sorry for the bug.

but we can change it

Always you can call the method explicitly with ().

Updated by tenderlovemaking (Aaron Patterson) almost 11 years ago

Ok! I will fix the code in Rails. Thank you!

Updated by tenderlovemaking (Aaron Patterson) almost 11 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) almost 11 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
Actions #13

Updated by nobu (Nobuyoshi Nakada) over 9 years ago

  • Related to Bug #11074: Block with optional parameter of same closure variable name added
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0