Re: Why nil


(Ken D'Ambrosio) #1

Hello, let's look at an example

class A
attr_accessor :a

def initialize(a)
@a = a
end

def method1(val)
a = val
end

def method2(val)
a = a + val
end
end

a = A.new(1)
a.method1(2) #=> 3
a.method2(2) #=> undefined method `+' for nil:NilClass

Why the second a is nil?

NOTE: I am not a programmer; I just dabble. But, unless I miss my mark,
the "a" being used in the initialization isn't available elsewhere in
the class. So, when you say
a = a + val
you are, in essence, saying
undefinedvariable = undefinedvariable + val
Which is a non-starter.
Let's check:
[1] pry(main)> class Foo
[1] pry(main)* def initialize(a)
[1] pry(main)* @a = a
[1] pry(main)* end
[1] pry(main)* def method1()
[1] pry(main)* puts a
[1] pry(main)* end
[1] pry(main)* end
=> :method1
[2] pry(main)> bar = foo.new(5)
NameError: undefined local variable or method `foo' for main:Object
from (pry):9:in `__pry__'
[3] pry(main)> bar = Foo.new(5)
=> #<Foo:0x000055916a3fc220 @a=5>
[4] pry(main)> bar.method1
NameError: undefined local variable or method `a' for
#<Foo:0x000055916a3fc220 @a=5>
Did you mean? @a
from (pry):6:in `method1'

The fact that (if I had used attr_accessor) ":a" can be accessible as
foo.a is simply a nicety of attr_accessor; it doesn't reflect what's
going on in the class, itself.

I'm sure, if I'm mistaken, someone will show me the error of my ways,

-Ken

···

On 2018-07-04 08:06, dade wrote:

dade.

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>


(Matthew Kerwin) #2

Hello, let's look at an example

class A
  attr_accessor :a

  def initialize(a)
    @a = a
  end

  def method1(val)
    a = val
  end

  def method2(val)
    a = a + val
  end
end

a = A.new(1)
a.method1(2) #=> 3
a.method2(2) #=> undefined method `+' for nil:NilClass

Why the second a is nil?

NOTE: I am not a programmer; I just dabble. But, unless I miss my mark, the "a" being used in the initialization isn't available elsewhere in the class. So, when you say
a = a + val
you are, in essence, saying
undefinedvariable = undefinedvariable + val

Two things:

1. there's no such thing as an undefined variable to the left of an
assignment. `a =` explicitly defines the variable `a`

2. by the time the interpreter gets to the second `a` it *is* defined,
because of the `a =` that immediately precedes it. However it's not
*initialised* yet.

Which is a non-starter.

[snip]

The fact that (if I had used attr_accessor) ":a" can be accessible as foo.a is simply a nicety of attr_accessor; it doesn't reflect what's going on in the class, itself.

Third thing:

3. the `attr_accessor :a` has defined `#.a` and `#.a=` methods,
however in this code neither of them are being called because Ruby
biases towards local variables; so `a =` will always define/assign to
a local variable, and any bare `a` (i.e. with no receiver nor
parentheses) that comes after it will always use that local variable.

These would work as (presumably?) intended:

~~~ruby
  def method1(val)
    self.a = val
  end

  def method2(val)
    self.a = self.a + val
    # OR:
    #self.a = a() + val
  end

···

On Mon, 3 Dec 2018 at 14:47, Ken D'Ambrosio <ken@jots.org> wrote:

On 2018-07-04 08:06, dade wrote:

~~~

I'm sure, if I'm mistaken, someone will show me the error of my ways,

-Ken

dade.

Not mistaken, just glossing some of the finesse.

Cheers
--
  Matthew Kerwin
  https://matthew.kerwin.net.au/