> We already have the simplifying rule that nil is false, anything > else is true. This just takes it one step further.
Actually false is also false, but in any case, I don't follow what you're saying here. Why is eating/ignoring messages a step further than being false?
I've always found the "undefined method 'blah' for nil:NilClass" message very handy, since certain things like uninitialized array elements are nil -- so it can help you catch errors. I don't know how it plays out in Smalltalk and/or Objective-C in that regard.
David Black
Eating messages is *bad*. Tons of my code would be infinitely harder to track down bugs in if this were default behavior.
I guarantee that
PDF::Writer would have been almost impossible to debug if this were the case. I don't think that this is a good idea in the least. Convince me otherwise. -Austin Ziegler
Eating messages is not necessarily bad, but it does come at the problem from a different (more Smalltalk-ish) point of view. I have a mild concern that working code could get broken by this, but mostly I think it would just break broken code in different ways. I think the style improvement I've seen in trying this idea out on some of my own code outweighs that risk.
As an alternative, adding a NullObjectClass that is a message eating class would be useful. A quick look at my own code suggests that it would be simplified noticeably by replacing all my uses of special case NullObjects with a generic NullObject.
Given the chosen behavior of nil in languages that share a lot of style with Ruby (Smalltalk and Objective-C), I favor changing the default behavior of nil.
As for the array initialization bit: When I was looking through some of my own recent code to consider the impact of this proposal, I encountered several examples where my array usage would be simplified by having nil be a classic NullObject and eat the messages.
> I don't follow what you're saying here.
nil and anything other than false is already overloaded to be both what it is, and a boolean type.
Thus we do have to say...
if fred != nil
#do stuff
end
we just say...
if fred
# do stuff.
end
-- > Tons of my code would be infinitely harder to track down bugs
Would it be so bad? I suspect in several cases not throwing a NoMethodError and doing nothing is the correct thing to do.
ie. Your bug was at some point or at some (possibly higher level) you did
fred.dostuff
when you should have done
fred.dostuff unless fred
In other words, in many cases this change will in many cases simply and silently convert existing buggy code in correct code.
ie. Ruby programs will in general crash less often.
Actually explore some of your code and investigate what would happen if this change was implemented. Select at random say twenty nil check guard statements and contemplate what would happen if this change was implemented AND you simply deleted that if statement.
I willing to bet in most cases (admittedly not all), your code would be simpler, and it would still do the right thing.
What is more, in the cases where you haven't put an if check, (ie. you have a bug) this change will change the bug from a crash into silently doing the right thing.
When I say "foo.do_stuff", I want stuff done. I don't want something *not* done.
If I got nil, somehow, then that's an error. I *want* an exception thrown.
You keep saying that this is "doing the right thing." I argue that it is exactly the wrong thing; there's nothing right about nil being a message eater in my programs and libraries. The error wasn't that I do:
foo.do_something
instead of:
foo.do_something if foo
The error was that somehow, foo was improperly set to nil. More, what you're saying I should *really* be doing is:
foo.do_something if foo.respond_to?(:do_something)
And therein lies the problem I have with this proposal. This forces me to start doing method checks. Sorry, but Ruby provides me a robust way of dealing with this sort of error: it DIES. -Austin
Prove it one way or the other by trying it the next couple of times you hit an undefined method for nil error. Let's not just work on theory here. Try it.
If I'm empirically proved wrong, I'll gladly retract this RCR. My experience suggests I won't be.
I'm not working on theory. I'm working on fact. The code in question no longer exists as of two or three days ago -- I fixed the bugs that were illustrated (and no, there's not even revision history evidence of this). But your theory gets blown apart the moment that I have to start dealing with values that will be output to the real world.
pdf = PDF::Writer
pagenum = pdf.which_page_number
pagenum -= 5
This code is invalid, because #which_page_number returns +nil+ if page numbering is turned off. In this case, it can't simply return zero -- that's a meaningful value for page numbering. Your proposal, however, will either mean that pagenum remains nil, or pagenum becomes -5, depending on what version you think would be the case with what you've said on ruby-talk. But the upshot is that someone does an operation on pagenum (rightly or wrongly) and gets an unexpected value by doing an integer operation on nil. As I said on ruby-talk, it's a nothing object -- not an anything object. One cannot subtract something from nothing. One cannot (meaningfully) tell nothing to #do_something.
You're wanting to mask a NoMethodError, saying it will reduce the number of bugs. I'm saying that it only means that programs won't fail with NoMethodError, but the bugs introduced will be far more subtle because operations appeared to succeed when they should not have succeeded. More to the point, the debugging of such things becomes nearly impossible because you have no starting point to know *when* the data when bad. (My point of using PDF::Writer with this discussion is very important. The output from an 80k text file -- the manual -- is a 400k uncompressed PDF that is full of circular references and very hard to read, or a 70k compressed PDF. That's the *only* way that I will ever be able to tell that something has broken using the feature you have requested here. -Austin
I am withdrawing this RCR for now.
With feedback from the community I believe it needs working on.
I'm currently developing and testing an alternate proposal based on creating a seperate "Nothing" class to differentiate it from NilCLass which is overloaded to mean both Unitialized and No Thing Here.
Watch the RCR space for more...
Actually false is also false, but in any case, I don't follow what you're saying here. Why is eating/ignoring messages a step further than being false?
I've always found the "undefined method 'blah' for nil:NilClass" message very handy, since certain things like uninitialized array elements are nil -- so it can help you catch errors. I don't know how it plays out in Smalltalk and/or Objective-C in that regard.
David Black
Eating messages is *bad*. Tons of my code would be infinitely harder to track down bugs in if this were default behavior.
I guarantee that PDF::Writer would have been almost impossible to debug if this were the case. I don't think that this is a good idea in the least. Convince me otherwise. -Austin Ziegler
Eating messages is not necessarily bad, but it does come at the problem from a different (more Smalltalk-ish) point of view. I have a mild concern that working code could get broken by this, but mostly I think it would just break broken code in different ways. I think the style improvement I've seen in trying this idea out on some of my own code outweighs that risk.
As an alternative, adding a NullObjectClass that is a message eating class would be useful. A quick look at my own code suggests that it would be simplified noticeably by replacing all my uses of special case NullObjects with a generic NullObject.
Given the chosen behavior of nil in languages that share a lot of style with Ruby (Smalltalk and Objective-C), I favor changing the default behavior of nil.
As for the array initialization bit: When I was looking through some of my own recent code to consider the impact of this proposal, I encountered several examples where my array usage would be simplified by having nil be a classic NullObject and eat the messages.
> I don't follow what you're saying here.
nil and anything other than false is already overloaded to be both what it is, and a boolean type.
Thus we do have to say...
we just say...-- > Tons of my code would be infinitely harder to track down bugs
Would it be so bad? I suspect in several cases not throwing a NoMethodError and doing nothing is the correct thing to do.
ie. Your bug was at some point or at some (possibly higher level) you did
when you should have doneIn other words, in many cases this change will in many cases simply and silently convert existing buggy code in correct code.
ie. Ruby programs will in general crash less often.
Actually explore some of your code and investigate what would happen if this change was implemented. Select at random say twenty nil check guard statements and contemplate what would happen if this change was implemented AND you simply deleted that if statement.
I willing to bet in most cases (admittedly not all), your code would be simpler, and it would still do the right thing.
What is more, in the cases where you haven't put an if check, (ie. you have a bug) this change will change the bug from a crash into silently doing the right thing.
When I say "foo.do_stuff", I want stuff done. I don't want something *not* done.
If I got nil, somehow, then that's an error. I *want* an exception thrown.
You keep saying that this is "doing the right thing." I argue that it is exactly the wrong thing; there's nothing right about nil being a message eater in my programs and libraries. The error wasn't that I do:
instead of:
The error was that somehow, foo was improperly set to nil. More, what you're saying I should *really* be doing is:
And therein lies the problem I have with this proposal. This forces me to start doing method checks. Sorry, but Ruby provides me a robust way of dealing with this sort of error: it DIES. -Austin
Prove it one way or the other by trying it the next couple of times you hit an undefined method for nil error. Let's not just work on theory here. Try it.
If I'm empirically proved wrong, I'll gladly retract this RCR. My experience suggests I won't be.
I'm not working on theory. I'm working on fact. The code in question no longer exists as of two or three days ago -- I fixed the bugs that were illustrated (and no, there's not even revision history evidence of this). But your theory gets blown apart the moment that I have to start dealing with values that will be output to the real world.
This code is invalid, because #which_page_number returns +nil+ if page numbering is turned off. In this case, it can't simply return zero -- that's a meaningful value for page numbering. Your proposal, however, will either mean that pagenum remains nil, or pagenum becomes -5, depending on what version you think would be the case with what you've said on ruby-talk. But the upshot is that someone does an operation on pagenum (rightly or wrongly) and gets an unexpected value by doing an integer operation on nil. As I said on ruby-talk, it's a nothing object -- not an anything object. One cannot subtract something from nothing. One cannot (meaningfully) tell nothing to #do_something.
You're wanting to mask a NoMethodError, saying it will reduce the number of bugs. I'm saying that it only means that programs won't fail with NoMethodError, but the bugs introduced will be far more subtle because operations appeared to succeed when they should not have succeeded. More to the point, the debugging of such things becomes nearly impossible because you have no starting point to know *when* the data when bad. (My point of using PDF::Writer with this discussion is very important. The output from an 80k text file -- the manual -- is a 400k uncompressed PDF that is full of circular references and very hard to read, or a 70k compressed PDF. That's the *only* way that I will ever be able to tell that something has broken using the feature you have requested here. -Austin
I am withdrawing this RCR for now.
With feedback from the community I believe it needs working on.
I'm currently developing and testing an alternate proposal based on creating a seperate "Nothing" class to differentiate it from NilCLass which is overloaded to mean both Unitialized and No Thing Here.
Watch the RCR space for more...