# attr\_accessor and NoMethodError

**URL:** <https://metaruby.com/t/attr-accessor-and-nomethoderror/392>\
**Category:** Ruby Chat\
**Created:** [November 24, 2015, 9:17pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392 "2015-11-24T21:17:35Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ohm](https://metaruby.com/user_avatar/metaruby.com/ohm/32/828_2.png) [@Ohm](https://metaruby.com/u/Ohm)\
**Post date:** [November 24, 2015, 9:17pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/1 "2015-11-24T21:17:35Z")

</div>

What am I missing here?

I have the following class

```auto
class Foo
  attr_accessor :x

  def initialize(x)
    @x = x
  end

  def count_down
    x -= 1
  end
end

```

If I then do

```auto
f = Foo.new(3)
f.count_down

```

I thought that I would decrement the `x` and then return `2`, however I  
get `NoMethodError: undefined method '-' for nil:NilClass` instead.

I thought that the `attr_accessor` just gave me a `x` and `x=` method,  
which read and wrote to `@x`.

Even if I switch the `count_down` definition to:

```auto
def count_count
  x = x - 1
end

```

it fails with the same `NoMethodError`.

* * *

The implementation works, if you substitute the first `x` in `count_down` with either `self.x` or `@x`. However, as I stated above, I thought that `attr_accessor` gave me the following methods:

```auto
def x
  @x
end

def x=(other)
  @x = other
end 

```

and the line in `count_down` should in my opinion call `x=` with the `x-1`, where the `x` is calling the `x` method, retrieving `@x` and subtracting `1`.

Shouldn’t Ruby look for all possible methods and variables, before declaring that the `x =` means “assign a new variable”?

---

<div class="post-metadata">

**Author:** ![Ohm](https://metaruby.com/user_avatar/metaruby.com/ohm/32/828_2.png) [@Ohm](https://metaruby.com/u/Ohm)\
**Post date:** [November 24, 2015, 9:19pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/2 "2015-11-24T21:19:15Z")

</div>

… the funny part is also the error message, which states that `NoMethodError: undefined method '-' for nil:NilClass`, which seems to indicate that it is the second `x`, which is read as `nil`, instead of the err being with the assigning part.

---

<div class="post-metadata">

**Author:** ![danielpclark](https://metaruby.com/user_avatar/metaruby.com/danielpclark/32/823_2.png) [@danielpclark](https://metaruby.com/u/danielpclark)\
**Post date:** [November 24, 2015, 9:50pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/4 "2015-11-24T21:50:42Z")

</div>

Here’s something interesting.

```ruby
class Foo
  def initialize(x)
    @x = x
  end
  def inspect_x
    puts defined?(x)
    puts defined?(self.x)
    puts defined?(@x)
  end
  def x
    puts :reader
    @x
  end
  def x=(y)
    puts :writer
    @x = y
  end
  def cdx
    x -= 1
  end
  def cdselfx
    self.x -= 1
  end
  def cdatx
    @x -= 1
  end
end

x = Foo.new(3)
# => #<Foo:0x00000001381b60 @x=3> 

x.inspect_x
#method
#method
#instance-variable

x.cdx
#NoMethodError: undefined method `-' for nil:NilClass

x.cdselfx
#reader
#writer
# => 2 
x.cdselfx
#reader
#writer
# => 1 

x = Foo.new(3)
# => #<Foo:0x000000012fc438 @x=3> 
x.cdatx
# => 2 
x.cdatx
# => 1 

```

For some reason since you’re using assignment on an instance variable the instance reference is required regardless of whether you use the method or instance variable.

---

<div class="post-metadata">

**Author:** ![danielpclark](https://metaruby.com/user_avatar/metaruby.com/danielpclark/32/823_2.png) [@danielpclark](https://metaruby.com/u/danielpclark)\
**Post date:** [November 24, 2015, 9:58pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/5 "2015-11-24T21:58:20Z")

</div>

If you add this method you can see the writer method isn’t getting called. x becomes a local (scope) variable, rather than the instance variable or method, when assigned.

```ruby
class Foo
  def count_down
    y = x
    x = y-1
  end
end

x = Foo.new(3)

x.count_down
#reader
# => 2 
x.count_down
#reader
# => 2 

```

With some inspection

```ruby
class Foo
  def count_down
    y = x
    x = y-1
    puts defined?(x)
    x
  end
end

x = Foo.new(3)

x.count_down
#reader
#local-variable
# => 2 
x.count_down
#reader
#local-variable
# => 2 

```

So to answer your question the `-=` operand takes x (local variable nil) to perform itself on. I just learned this myself. I don’t use **attr** methods… maybe ever.

---

<div class="post-metadata">

**Author:** ![Ohm](https://metaruby.com/user_avatar/metaruby.com/ohm/32/828_2.png) [@Ohm](https://metaruby.com/u/Ohm)\
**Post date:** [November 25, 2015, 7:56am UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/6 "2015-11-25T07:56:22Z")

</div>

Yeah, so my question is:

> [@Ohm](#):
>
> Shouldn’t Ruby look for all possible methods and variables, before declaring that the x = means “assign a new variable”?

When I type `x =` Ruby should probably check if there is a `self.x=` method, before assuming `x` is a new local variable.

---

<div class="post-metadata">

**Author:** ![AstonJ](https://metaruby.com/user_avatar/metaruby.com/astonj/32/8_2.png) [@AstonJ](https://metaruby.com/u/AstonJ)\
**Post date:** [November 25, 2015, 12:06pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/7 "2015-11-25T12:06:49Z")

</div>

> [@Ohm](#):
>
> Yeah, so my question is:
> 
> Ohm:  
> Shouldn’t Ruby look for all possible methods and variables, before declaring that the x = means “assign a new variable”?
> 
> When I type x = Ruby should probably check if there is a self.x= method, before assuming x is a new local variable.

Do you think that might encourage (perhaps accidentally) inconsistent code? I think I prefer it as it is tbh…

---

<div class="post-metadata">

**Author:** ![Ohm](https://metaruby.com/user_avatar/metaruby.com/ohm/32/828_2.png) [@Ohm](https://metaruby.com/u/Ohm)\
**Post date:** [November 25, 2015, 12:19pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/8 "2015-11-25T12:19:53Z")

</div>

> [@AstonJ](#):
>
> Do you think that might encourage (perhaps accidentally) inconsistent code? I think I prefer it as it is tbh…

I think you’re right. I just got caught in this simple trap writing some code yesterday. If you have a large class with many `attr_reader`, `attr_writer` and `attr_accessor`, it might get overwhelming to check all the instance variables before creating local variables.

---

<div class="post-metadata">

**Author:** ![kofno](https://metaruby.com/user_avatar/metaruby.com/kofno/32/159_2.png) [@kofno](https://metaruby.com/u/kofno)\
**Post date:** [November 25, 2015, 1:46pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/9 "2015-11-25T13:46:23Z")

</div>

This is an oldie but a goodie. Since variable assignment also creates a variable instance, you just have to be explicit with the scope (self).

This has led many ruby dsl authors don’t write setters, and instead dual purpose the getter with an optional argument.

---

<div class="post-metadata">

**Author:** ![Ohm](https://metaruby.com/user_avatar/metaruby.com/ohm/32/828_2.png) [@Ohm](https://metaruby.com/u/Ohm)\
**Post date:** [November 25, 2015, 2:07pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/10 "2015-11-25T14:07:36Z")

</div>

> [@kofno](#):
>
> This has led many ruby dsl authors don’t write setters, and instead dual purpose the getter with an optional argument.

I can see why. 😏

```auto
class Foo
  def initialize(x)
    @x = x
  end

  def x(*args)
    return @x if args.empty?
    @x = args.first
  end
  
  def count_down
    x(x - 1)
   end
end

```

Now my `count_down` works. (Granted, in this simple case `self.x` or `@x` might have been better.)

---

<div class="post-metadata">

**Author:** ![ludovic](https://metaruby.com/user_avatar/metaruby.com/ludovic/32/183_2.png) [@ludovic](https://metaruby.com/u/ludovic)\
**Post date:** [November 25, 2015, 5:04pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/11 "2015-11-25T17:04:56Z")

</div>

Normal behavor into Ruby world.

Accessor are here for outside access. Use self.x in this case (self access your object from outside, so you get access only to public methods). Without accessor, use @x to access your Instance Variable. It’s the normal way in Ruby. You define a @variable, you use @variable in your code.

In your case (x -= 1), internally, Ruby first get the x object (here x don’t exist, so it’s initialized to nil), and attempt to call on x the method “-” with your parameter (here 1). The fact that Ruby decompose this simple line in two actions can be checked here :

In irb, type :

```ruby
x # You get undefined local variable or method x
x += 1 # You get the undefined method + for nil class
x # You get nil. Ruby in it's first action has created your x variable to nil

```

Great, no ?

This is why you get this strange error about a missing method : Numeric objects have the “-” method (and lot of other, but it’s not our problem here). Nill object have not. So you get a method error. Really, it’s normal.

In irb, try to do :

```ruby
1.respond_to? :-

```

Prefer use @x in your code and let the use of your accessors for outside access only.  
Always use self when you want use setter following assignment signature, in short : Any method name ending with “=”… And especially if you use object with dynamic method generation like ActiveRecord does (at least, one method ending with “=” for each field).

I hope this help you.  
Ludovic.

---

<div class="post-metadata">

**Author:** ![ludovic](https://metaruby.com/user_avatar/metaruby.com/ludovic/32/183_2.png) [@ludovic](https://metaruby.com/u/ludovic)\
**Post date:** [November 26, 2015, 3:29pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/12 "2015-11-26T15:29:56Z")

</div>

Prefer this code :

```ruby
class Foo
  attr_accessor :x
  def initialize(x=0)
    @x = x if x.is_a? Numeric
    @x ||= 0
  end

  def count_down
    @x -= 1
  end
end

```

---

<div class="post-metadata">

**Author:** ![danielpclark](https://metaruby.com/user_avatar/metaruby.com/danielpclark/32/823_2.png) [@danielpclark](https://metaruby.com/u/danielpclark)\
**Post date:** [November 26, 2015, 5:30pm UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/13 "2015-11-26T17:30:52Z")

</div>

Same kind of thing in the global namespace.

```ruby
public def x
  puts :reader
  $x
end

public def x=(other)
  puts :writer
  $x = other
end

$x = 3

x -= 1
#NoMethodError: undefined method `-' for nil:NilClass
x
# => nil
self.x
#reader
# => 3
self.x -= 1
#reader
#writer
# => 2 
self.x
#reader
# => 2

```

---

<div class="post-metadata">

**Author:** ![danielpclark](https://metaruby.com/user_avatar/metaruby.com/danielpclark/32/823_2.png) [@danielpclark](https://metaruby.com/u/danielpclark)\
**Post date:** [June 24, 2016, 5:35am UTC](https://metaruby.com/t/attr-accessor-and-nomethoderror/392/14 "2016-06-24T05:35:08Z")

</div>

And then there’s `send`

```ruby
class Foo
  attr_accessor :x

  def initialize(x)
    @x = x
  end

  def count_down
    send :x=, x()-1
  end
end
a = Foo.new(3)
puts a.count_down
# => 2
puts a.count_down
# => 1

```
