Discussion:
Why nil
dade
2018-07-04 12:06:39 UTC
Permalink
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?



dade.
Tanguy Andreani
2018-07-04 12:26:19 UTC
Permalink
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Stefano Crocco
2018-07-04 12:41:30 UTC
Permalink
Post by dade
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?
dade.
Why should it be something else than nil? inside method2, a is a local
variable. To execute the line a = a + val, ruby first compute the right hand
side of the expression, which is a + val. Since you haven't given a value to
the variable a, it is implicitly set to nil. Ruby then tries to sum nil to
value and it fails.

I think that you expected method1 and method2 to call the accessor methods,
but this is not what happens. When ruby sees a = ..., it assumes that a is a
local variable, and doesn't even notice that there are methods called "a" and
"a=". To avoid this and have the accessor methods called from method1 and
method2, you have to explicitly tell ruby those "a" are methods by calling
them with the dot notation (using self as receiver):

class A
attr_accessor :a

def initialize(a)
@a = a
end

def method1(val)
self.a = val
end

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

I hope this helps

Stefano



Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Andy Jones
2018-07-04 13:02:17 UTC
Permalink
Post by Stefano Crocco
I think that you expected method1 and method2 to call the accessor methods,
This is why I prefer to always use @ to refer to attributes inside their class, contrary to what some quite respected Rubyists suggest.


Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Dmitriy Non
2018-07-04 19:04:24 UTC
Permalink
The problem is that setter/getter can become more complicated
than just assigning or getting value.

If your code uses getter/setter more than 1 time you should not use
instance variable directly.

In the end, using it directly has no benefits at all if you know ruby.
Well, except for absence of one code line `attr_accessor :a`.
--------------------------------------
Dmitriy Non
Post by Stefano Crocco
I think that you expected method1 and method2 to call the accessor methods,
This is why I prefer to always use @ to refer to attributes inside their class, contrary to what some quite respected Rubyists suggest.


Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

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


Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Andy Jones
2018-07-05 07:21:56 UTC
Permalink
The problem is that setter/getter can become more complicated
than just assigning or getting value.

If your code uses getter/setter more than 1 time you should not use
instance variable directly.

In the end, using it directly has no benefits at all if you know ruby.
Well, except for absence of one code line `attr_accessor :a`.
<<<<

But as already noted, you are forced to use @var = 1 and not var = 1 inside the class. I agree it might be nice to abstract out attributes to their getters and setters inside the class, but since you can only do it for getters, the value of that is limited.

Also, the abstraction is mildly confusing. If I have an attribute @foo in a subclass and I make reference to foo, without the @, is that a getter? Or is it something defined in the superclass? Or in a mixin? I have to look at the whole class definition, at least, to check.

Final point: surely the only legitimate reason to use attr_accessor etc is if something _outside_ of the class needs to access the attribute? I know Ruby doesn't do strong encapsulation, but, even so...



Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Wolf
2018-07-08 12:14:24 UTC
Permalink
Post by Dmitriy Non
The problem is that setter/getter can become more complicated
than just assigning or getting value.
If your code uses getter/setter more than 1 time you should not use
instance variable directly.
In the end, using it directly has no benefits at all if you know ruby.
Well, except for absence of one code line `attr_accessor :a`.
<<<<
Why are you forced to do that? You can just use `self.var = 1`.

W.
--
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.
Robert Klemme
2018-07-09 14:30:51 UTC
Permalink
Post by Wolf
Post by Dmitriy Non
The problem is that setter/getter can become more complicated
than just assigning or getting value.
If your code uses getter/setter more than 1 time you should not use
instance variable directly.
In the end, using it directly has no benefits at all if you know ruby.
Well, except for absence of one code line `attr_accessor :a`.
<<<<
Why are you forced to do that?
Because it's the way the language is built.
Post by Wolf
You can just use `self.var = 1`.
You can, but then you need a method "var=" and the state needs to be
stored somewhere, presumably in an instance variable @var.

Cheers

robert
--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Ryan Davis
2018-07-09 19:38:01 UTC
Permalink
Post by Robert Klemme
Post by Wolf
Post by Dmitriy Non
The problem is that setter/getter can become more complicated
than just assigning or getting value.
If your code uses getter/setter more than 1 time you should not use
instance variable directly.
In the end, using it directly has no benefits at all if you know ruby.
Well, except for absence of one code line `attr_accessor :a`.
<<<<
Why are you forced to do that?
Because it's the way the language is built.
Post by Wolf
You can just use `self.var = 1`.
You can, but then you need a method "var=" and the state needs to be
I’m not sure why you’re phrasing any of this this way. Given the OP’s original code, it was ALREADY structured that way and the advice given by Gonzola and Wolf was spot on. Your “yes but” seems ill-placed and, if anything, should be directed at all the responses that say you’re forced to use @vars (which I always eschew when possible).


Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lan
Ryan Davis
2018-07-09 19:39:24 UTC
Permalink
That is decidedly false: `self.var = 1`. The ONLY place you’re “forced” to use an ivar, is in the implementation of a custom setter:

def var= o
@var = calculate o
end


Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bi
Andy Jones
2018-07-11 07:35:56 UTC
Permalink
Folks, I was stating a personal preference. I think I'm allowed those. Not attacking anyone. If I want to use @attribute = "foo" and not self.attribute = "foo" inside a class, that's not objectively wrong. It's my personal choice.


Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Xavier Noria
2018-07-11 07:54:01 UTC
Permalink
On Wed, Jul 11, 2018 at 9:35 AM, Andy Jones <***@jameshall.co.uk>
wrote:

Folks, I was stating a personal preference. I think I'm allowed those.
Post by Andy Jones
self.attribute = "foo" inside a class, that's not objectively wrong. It's
my personal choice.
FWIW I use ivars often too, tend to define accessors only if they are
public interface.

Even further, if the test suite of the class needs to set state by
reading/writing an ivar for whatever reason, and that is the only code
accessing them outside the class, I still stick to ivars and use
instance_variable_get/set. That is because my public interface is strictly
defined by client code and in my book a test is not client code, and
because I believe it is OK that the test suite knows the ivars of the class
it is covering if the interface so requires it.

Other people with different style/preferences, fine!
Andy Jones
2018-07-11 07:59:39 UTC
Permalink
That is because my public interface is strictly defined by client code and in my book a test is not client code, and because I believe it is OK that the test suite knows the ivars of the class it is covering if the interface so requires it.
<<<<<<

I had that conversation with myself a while ago and decided that my tests _were_ client code, just as important as the other classes that called that class.

Either way seems like a perfectly valid call to me



Click here to view Company Information and Confidentiality Notice.<http://www.jameshall.co.uk/index.php/small-print/email-disclaimer>

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
Robert Klemme
2018-07-11 12:41:04 UTC
Permalink
Post by Andy Jones
That is because my public interface is strictly defined by client code and in my book a test is not client code, and because I believe it is OK that the test suite knows the ivars of the class it is covering if the interface so requires it.
<<<<<<
I had that conversation with myself a while ago and decided that my tests _were_ client code, just as important as the other classes that called that class.
I'm too old for religious wars but I will say that I tend to view test
code not as a first class client. But: I usually create class
interfaces as abstract data types and there you typically define one
constraint in a number of operations; if you do that then I believe
this will support testing. After all, you want to ensure that the
observed behavior is as intended and not poke into the innards of the
implementation. If there are cases where an occasional additional
method is needed for some validation I won't commit Seppuku over this.
:-)
Post by Andy Jones
Either way seems like a perfectly valid call to me…
Right, we're still in the land of the Pragmatic Programmer, aren't we?

Kind regards

robert

https://pragprog.com/book/tpp/the-pragmatic-programmer
--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.
Sarkar Chinmoy
2018-07-13 17:46:45 UTC
Permalink
Please do NOT send any more e-mail to me. Thanks.Chinmoy
On Wednesday, July 11, 2018, 2:59:58 AM CDT, Andy Jones <***@jameshall.co.uk> wrote:

#yiv1542432271 #yiv1542432271 -- _filtered #yiv1542432271 {font-family:Calibri;panose-1:2 15 5 2 2 2 4 3 2 4;}#yiv1542432271 #yiv1542432271 p.yiv1542432271MsoNormal, #yiv1542432271 li.yiv1542432271MsoNormal, #yiv1542432271 div.yiv1542432271MsoNormal {margin:0cm;margin-bottom:.0001pt;font-size:12.0pt;font-family:New;}#yiv1542432271 a:link, #yiv1542432271 span.yiv1542432271MsoHyperlink {color:blue;text-decoration:underline;}#yiv1542432271 a:visited, #yiv1542432271 span.yiv1542432271MsoHyperlinkFollowed {color:purple;text-decoration:underline;}#yiv1542432271 span.yiv1542432271EmailStyle17 {color:#1F497D;}#yiv1542432271 .yiv1542432271MsoChpDefault {} _filtered #yiv1542432271 {margin:72.0pt 72.0pt 72.0pt 72.0pt;}#yiv1542432271 div.yiv1542432271WordSection1 {}#yiv1542432271
 
That is because my public interface is strictly defined by client code and in my book a test is not client code, and because I believe it is OK that the test suite knows the ivars of the class it is covering if the interface so requires it.
<<<<<<  

 

I had that conversation with myself a while ago and decided that my tests _were_ client code, just as important as the other classes that called that class. 

 

Either way seems like a perfectly valid call to me



Click here to view Company Information and Confidentiality Notice.

Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.

Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Ken D'Ambrosio
2018-07-13 19:57:03 UTC
Permalink
Please DO NOT send any more e-mail to me. Thanks.
_Chinmoy_
You are subscribed to a Ruby mailing list; as long as the list is active
(which I hope is for some time to come), you will receive e-mail. At
the bottom of every e-mail you receive from the list -- including this
one when it comes through the list -- are the following two lines:

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

E-mail to the first, or click on the second, and you can unsubscribe.

Mailing the list, alas, simply generates more e-mail. (Indeed, mail
storms sometimes occur from people who don't quite get this. But this
list is low-volume enough I'm not overly worried, and, sometimes, it
doesn't hurt to remind folks at large how to go about unsubscribing.)

Have a pleasant weekend!

-Ken
That is because my public interface is strictly defined by client code and in my book a test is not client code, and because I believe it is OK that the test suite knows the ivars of the class it is covering if the interface so requires it.
<<<<<<
I had that conversation with myself a while ago and decided that my tests __were__ client code, just as important as the other classes that called that class.
Either way seems like a perfectly valid call to me...
Click here to view Company Information and Confidentiality Notice. [1]
Please note that we have updated our privacy policy in line with new data protection regulations. Please refer to our website to view the ways in which we handle your data.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Links:
------
[1] http://www.jameshall.co.uk/index.php/small-print/email-disclaimer
Ryan Davis
2018-07-09 19:37:07 UTC
Permalink
Post by Stefano Crocco
I think that you expected method1 and method2 to call the accessor methods,
I’m one of those. I totally disagree with your assessment. Always use accessors and you have only one thing to change when you need to modify how storage is done, whether that’s adding caching, adding or offloading calculation, or just having a single point to add a breakpoint to debug.

Using instance variables directly everywhere means you’ve got N places you need to pay attention to, not 1. It also means that you’re using a double standard when it comes to accessing your state (assuming you still have a public accessor method) that can lead to inconsistencies. The only place you’ll find an “@“ in most of my code is inside of a custom setter method and that has worked out very very well for me over the long haul (looong before I was doing ruby, I was doing smalltalk, and this pattern comes from there).


Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/opti
Tanguy Andreani
2018-07-04 12:48:30 UTC
Permalink
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Saurav Kothari
2018-07-05 09:26:08 UTC
Permalink
Post by dade
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
You are trying to change the value of the instance variable @a I suppose?
But here you are using a local variable a that has not been defined yet.

end
Post by dade
end
a = A.new(1)
a.method1(2) #=> 3
How is this 3? This will return a 2, right?
Post by dade
a.method2(2) #=> undefined method `+' for nil:NilClass
Why the second a is nil?
Gonzalo Garramuño
2018-07-05 11:39:32 UTC
Permalink
Post by Saurav Kothari
How is this 3? This will return a 2, right?
a.method2(2) #=> undefined method `+' for nil:NilClass
Another possibility is to actually use the accessors with self, like:

self.a = self.a + val
--
Gonzalo Garramuño
Ken D'Ambrosio
2018-12-03 04:45:36 UTC
Permalink
Post by dade
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
Post by dade
dade.
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
Matthew Kerwin
2018-12-03 08:49:58 UTC
Permalink
Post by dade
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
~~~
I'm sure, if I'm mistaken, someone will show me the error of my ways,
-Ken
Post by dade
dade.
Not mistaken, just glossing some of the finesse.

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

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