[ruby-core:114333] [Ruby master Bug#19795] attr_accessor leading to nil values for re-assignment

Issue #19795 has been reported by francktrouillez (Franck Trouillez). ---------------------------------------- Bug #19795: attr_accessor leading to nil values for re-assignment https://bugs.ruby-lang.org/issues/19795 * Author: francktrouillez (Franck Trouillez) * Status: Open * Priority: Normal * ruby -v: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- ### Steps to reproduce: - Create a class with an `attr_accessor` for an instance variable - Create an instance method that reassign this variable using the current value stored in the variable - Show that the variable is set to nil during the evaluation Code snippet: ``` ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 1 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" a += 1 if a.positive? # use an integer method end end instance = A.new instance.my_method # output: # # a is '1' of class 'Integer' # attr_accessor_nil.rb:12:in `my_method': undefined method `positive?' for nil:NilClass (NoMethodError) # # a += 1 if a.positive? # use an integer method # ^^^^^^^^^^ # from attr_accessor_nil.rb:17:in `<main>' ``` ### Expected behavior `a += 1` should lead to `a` being equal to `1` at the end of the assignment, because `a` was storing `0` previously, as shown by the `puts`. Am I being wrong expecting this result? ### Actual behavior `a += 1` raises an error about `a` being `nil` in the evaluation. ### Further investigation I checked if it was coming from the "instance variable", or about the "attr_accessor" by running the following snippet: Code snippet: ```ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" @a += 1 # use the instance variable directly, instead of the accessor end end instance = A.new instance.my_method # output: # # a is '1' of class 'Integer' ``` This snippet runs just fine, and no error is raised. ### System configuration Ruby version : 3.2.2 -- https://bugs.ruby-lang.org/

Issue #19795 has been updated by nobu (Nobuyoshi Nakada). Status changed from Open to Closed This is an assignment to the local variable, not the accessor. ```ruby a += 1 ``` You have to write: ```ruby self.a += 1 ``` ---------------------------------------- Bug #19795: attr_accessor leading to nil values for re-assignment https://bugs.ruby-lang.org/issues/19795#change-104038 * Author: francktrouillez (Franck Trouillez) * Status: Closed * Priority: Normal * ruby -v: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- ### Steps to reproduce: - Create a class with an `attr_accessor` for an instance variable - Create an instance method that reassign this variable using the current value stored in the variable - Show that the variable is set to nil during the evaluation Code snippet: ``` ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" a += 1 end end instance = A.new instance.my_method # output: # # a is '0' of class 'Integer' # attr_accessor_nil.rb:12:in `my_method': undefined method `+' for nil:NilClass (NoMethodError) # # a += 1 # ^ # from attr_accessor_nil.rb:17:in `<main>' ``` ### Expected behavior `a += 1` should lead to `a` being equal to `1` at the end of the assignment, because `a` was storing `0` previously, as shown by the `puts`. Am I being wrong expecting this result? ### Actual behavior `a += 1` raises an error about `a` being `nil` in the evaluation. ### Further investigation I checked if it was coming from the "instance variable", or about the "attr_accessor" by running the following snippet: Code snippet: ```ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" @a += 1 # use the instance variable directly, instead of the accessor end end instance = A.new instance.my_method # output: # # a is '0' of class 'Integer' ``` This snippet runs just fine, and no error is raised. ### System configuration Ruby version : 3.2.2 -- https://bugs.ruby-lang.org/

Issue #19795 has been updated by francktrouillez (Franck Trouillez). I guess that it is a local variable, but is it the expected behavior? As a developer, I expect that I can access `a` without the `self.a`. Since the following code works as expected without `self`: ```ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" b = a + 1 a = 1 puts "b is '#{b.inspect}' of class '#{b.class}'" puts "a is '#{a.inspect}' of class '#{a.class}'" end end instance = A.new instance.my_method # output: # # a is '0' of class 'Integer' # b is '1' of class 'Integer' # a is '1' of class 'Integer' ``` I expect that the following works as well: ```ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" a = a + 1 end end instance = A.new instance.my_method # output: # # a is '0' of class 'Integer' # Traceback (most recent call last): # 1: from attr_accessor_nil.rb:17:in `<main>' # attr_accessor_nil.rb:12:in `my_method': undefined method `+' for nil:NilClass (NoMethodError) ``` Why can I access the instance variable (read and write) without the `self`, but as soon as I try to re-assign it using the current value, it switches to a local variable? This is something unexpected for me. Is it the expected behavior for this? If so, is there a way of making this special case clearer? Or am I being wrong thinking the behavior is unexpected? ---------------------------------------- Bug #19795: attr_accessor leading to nil values for re-assignment https://bugs.ruby-lang.org/issues/19795#change-104039 * Author: francktrouillez (Franck Trouillez) * Status: Closed * Priority: Normal * ruby -v: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- ### Steps to reproduce: - Create a class with an `attr_accessor` for an instance variable - Create an instance method that reassign this variable using the current value stored in the variable - Show that the variable is set to nil during the evaluation Code snippet: ``` ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" a += 1 end end instance = A.new instance.my_method # output: # # a is '0' of class 'Integer' # attr_accessor_nil.rb:12:in `my_method': undefined method `+' for nil:NilClass (NoMethodError) # # a += 1 # ^ # from attr_accessor_nil.rb:17:in `<main>' ``` ### Expected behavior `a += 1` should lead to `a` being equal to `1` at the end of the assignment, because `a` was storing `0` previously, as shown by the `puts`. Am I being wrong expecting this result? ### Actual behavior `a += 1` raises an error about `a` being `nil` in the evaluation. ### Further investigation I checked if it was coming from the "instance variable", or about the "attr_accessor" by running the following snippet: Code snippet: ```ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" @a += 1 # use the instance variable directly, instead of the accessor end end instance = A.new instance.my_method # output: # # a is '0' of class 'Integer' ``` This snippet runs just fine, and no error is raised. ### System configuration Ruby version : 3.2.2 -- https://bugs.ruby-lang.org/

Issue #19795 has been updated by francktrouillez (Franck Trouillez). I got it in the end thanks to a peer. I misunderstood wrongly how this was working: Running the following snippet helped me understand: ```ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" b = a + 1 a = b puts "b is '#{b.inspect}' of class '#{b.class}'" puts "a is '#{a.inspect}' of class '#{a.class}'" end def my_method_2 puts "a is '#{a.inspect}' of class '#{a.class}'" end end instance = A.new instance.my_method instance.my_method_2 # output: # # a is '0' of class 'Integer' # b is '1' of class 'Integer' # a is '1' of class 'Integer' # a is '0' of class 'Integer' ``` So, we cannot modify the instance variable through the accessor directly. If it was, the last `puts` should show `1` Thanks for your help! ---------------------------------------- Bug #19795: attr_accessor leading to nil values for re-assignment https://bugs.ruby-lang.org/issues/19795#change-104041 * Author: francktrouillez (Franck Trouillez) * Status: Closed * Priority: Normal * ruby -v: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN ---------------------------------------- ### Steps to reproduce: - Create a class with an `attr_accessor` for an instance variable - Create an instance method that reassign this variable using the current value stored in the variable - Show that the variable is set to nil during the evaluation Code snippet: ``` ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" a += 1 end end instance = A.new instance.my_method # output: # # a is '0' of class 'Integer' # attr_accessor_nil.rb:12:in `my_method': undefined method `+' for nil:NilClass (NoMethodError) # # a += 1 # ^ # from attr_accessor_nil.rb:17:in `<main>' ``` ### Expected behavior `a += 1` should lead to `a` being equal to `1` at the end of the assignment, because `a` was storing `0` previously, as shown by the `puts`. Am I being wrong expecting this result? ### Actual behavior `a += 1` raises an error about `a` being `nil` in the evaluation. ### Further investigation I checked if it was coming from the "instance variable", or about the "attr_accessor" by running the following snippet: Code snippet: ```ruby # attr_accessor_nil.rb class A attr_accessor :a def initialize @a = 0 end def my_method puts "a is '#{a.inspect}' of class '#{a.class}'" @a += 1 # use the instance variable directly, instead of the accessor end end instance = A.new instance.my_method # output: # # a is '0' of class 'Integer' ``` This snippet runs just fine, and no error is raised. ### System configuration Ruby version : 3.2.2 -- https://bugs.ruby-lang.org/
participants (2)
-
francktrouillez (Franck Trouillez)
-
nobu (Nobuyoshi Nakada)