No Thing Here vs Uninitialized and RCR 303

I'm observing a general trend in the responses to RCR 303.

The first and most striking is -w. I always, utterly and without fail, use
-w and had assumed incorrectly that everyone else did. (But then I always
use -W -Wall on gcc as well)

This fact I find curious given the storm of but "RCR 303 might mask a bug"
responses.

Now let us consider when a nil does arise in ruby....

Nil arises in several places that I can think of.

The most obvious case, and the case I think most people are concerned
about, is when referencing an uninitialized variable.

This case is flagged by -w, and hence I had mentally disregarded the
possibility when I wrote RCR 303.

The next case is when nil is returned by something like a regex match or
an index out of bounds.

The third case is when explicit set by the programmer, typically as a
default parameter to a method.

The fourth case is to get around the lexical scoping umfeature of rubies
local variables.

def foo
  my_var = nil
  box.each do |e|
    my_var = e if e.blah
  end

  use_var( my_var)
end

This is another case of "nil means uninitialized".

So what we have is a "nil" is a little too busy, means too much, is
overloaded too heavily.

It means "uninitialized".

It also means "no thing here" (as in return from regexp match (no
MatchData here), index out of bounds (no Array element here), and nil as a
default value.)

I perfectly agree that "uninitialized" should throw a
NoMethodError. Indeed I doubt if it should respond to some of the
methods it does respond to currently. I even think -w is too friendly, I
would prefer it to throw than to just warn.

What I as thinking of by RCR 303 is nil as "no thing here" should respond
to all methods, do nothing and return "no thing here".

So perhaps I should retract RCR 303 and created a new one suggesting and
differentiation between "uninitialized" and "no thing here", and
effectively RCR-303 for "no thing here".

I would welcome suggestions as to how to craft this new RCR.

···

--
John Carter

The Cybernetic Entomologist - cyent@xtra.co.nz

I'm becoming less and less convinced of humans as rational beings.
I suspect we are merely meme collectors, and the reason meme is only
kept on to help count our change.

Cyent schrieb:
..

def foo
my_var = nil
box.each do |e| my_var = e if e.blah
end

use_var( my_var)
end

This is another case of "nil means uninitialized".

...

So perhaps I should retract RCR 303 and created a new one suggesting and
differentiation between "uninitialized" and "no thing here", and
effectively RCR-303 for "no thing here".

You could ask for the creation of a separate "undefined" value similar
to the "undefined, "null" pair in Javascript

OT - doses anybody know whatever happen to Javascript 2.0? (please
don't kill me but I actually kind of like Javascript::slight_smile:

/Christoph

Hi --

Nil arises in several places that I can think of.

The most obvious case, and the case I think most people are concerned
about, is when referencing an uninitialized variable.

That pertains only to instance and global variables, and I don't
remember seeing a lot about it (though I haven't tallied the
responses).

This case is flagged by -w, and hence I had mentally disregarded the
possibility when I wrote RCR 303.

The next case is when nil is returned by something like a regex match or
an index out of bounds.

That seemed to me to be what people were talking about mostly --
things like:

    /som(e n)on-matc(hing) regex/.match("blah").captures

The third case is when explicit set by the programmer, typically as a
default parameter to a method.

The fourth case is to get around the lexical scoping umfeature of rubies
local variables.

def foo
my_var = nil
box.each do |e|
   my_var = e if e.blah
end

use_var( my_var)
end

This is another case of "nil means uninitialized".

It's not that, exactly; rather, you're initializing a variable to nil.
You've chosen nil to represent the initialized state of the variable,
not an uninitialized state. Once you assign to it, it's initialized.

So what we have is a "nil" is a little too busy, means too much, is
overloaded too heavily.

I'm not sure where the "too"s come from. How do you determine how
much (or little) use should be made of such a construct? You can
always initialize your variables to something else if you don't like
using nil too much :slight_smile:

It means "uninitialized".

It also means "no thing here" (as in return from regexp match (no
MatchData here), index out of bounds (no Array element here), and nil as a
default value.)

It's not exactly "no Array element here"; it's more a default value.
You can have nil as an array element; therefore, it cannot mean that
there's no element. As with hashes, of course, the retrieval of the
default value does not initialize the element:

    ruby -we 'a = ; a[3]; p a.size'
    0

I perfectly agree that "uninitialized" should throw a
NoMethodError.

That's not what happens, though. If a local variable is
uninitialized, you find out before you get to the point of sending it
a message:

   bash-2.04$ ruby -e 'a.b'
   -e:1: undefined local variable or method `a' for main:Object
   (NameError)

whereas NoMethodError happens when you send a message to an object.

Indeed I doubt if it should respond to some of the
methods it does respond to currently. I even think -w is too friendly, I
would prefer it to throw than to just warn.

What I as thinking of by RCR 303 is nil as "no thing here" should respond
to all methods, do nothing and return "no thing here".

So perhaps I should retract RCR 303 and created a new one suggesting and
differentiation between "uninitialized" and "no thing here", and
effectively RCR-303 for "no thing here".

I would welcome suggestions as to how to craft this new RCR.

A few years ago there was a discussion of some kind of NACK mechanism
-- meaning, something that an object could give as a reponse when it
didn't recognize a message, instead of raising NoMethodError. My main
goal was to avoid this:

    obj.meth if obj.respond_to?(:meth)

a repetition I've always disliked, and at the same time to avoid
having to do this:

    begin
      obj.meth
    rescue NoMethodError
      ...
    end

The big problem with NACK, though, was that it was incompatible with
method_missing: it offered a different way to handle the same
situation. Anyway, I thought the concept might be of interest in
connection with the problem you're working on, and perhaps you can
engineer it successfully.

David

···

On Sun, 8 May 2005, Cyent wrote:

--
David A. Black
dblack@wobblini.net

Cyent wrote:

So what we have is a "nil" is a little too busy, means too much, is
overloaded too heavily.

It means "uninitialized".

nil doesn't 'mean' anything. Assorted code uses nil to express a condition, and it is the context that confers meaning.

James

[...]

So what we have is a "nil" is a little too busy, means too much, is
overloaded too heavily.

It means "uninitialized".

It also means "no thing here" (as in return from regexp match (no
MatchData here), index out of bounds (no Array element here), and nil as a
default value.)

[...]

Interesting. While I'm not sure I would want the change in Ruby, this is presumably why Javascript has both the value 'undefined' (uninitialized) as well as 'null' (no value). null == undefined, but null !== undefined.

···

On May 8, 2005, at 1:04 AM, Cyent wrote:

Cyent a écrit :

I'm observing a general trend in the responses to RCR 303.

The first and most striking is -w. I always, utterly and without fail, use
-w and had assumed incorrectly that everyone else did. (But then I always
use -W -Wall on gcc as well)

I suppose it's easier to refuse an RCR than to change programming habits.

···

--
Lionel Thiry

Personal website: http://users.skynet.be/lthiry/

Christoph wrote:

You could ask for the creation of a separate "undefined" value similar
to the "undefined, "null" pair in Javascript

OT - doses anybody know whatever happen to Javascript 2.0? (please
don't kill me but I actually kind of like Javascript::slight_smile:

Don't worry, there's a secret society of JavaScript, um, ECMAScript[0], fans here.

Current ECMAScript is edition 3. According to [1]:
"Edition 4 is now expected to be released in Q3 2005. This will update the standard with respect to the language and the various differing implementations."

(The likely reality, though, is that browser vendors will continue to implement whatever they feel best serves them. If that coincides with recognized specs or standards, so much the better. )

James

[0] ECMA-262 - Ecma International
[1] http://www.ecma-international.org/news/4xpr-final-2004.htm

···

--

http://catapult.rubyforge.com
http://orbjson.rubyforge.com
http://ooo4r.rubyforge.com
http://www.jamesbritt.com

This isn't about changing programming habits. Having nil return nil
for missing methods can have serious consequences.

Consider:

   file = create_new_log_file
   file.log "here's a bit of information"

You're expecting this code to log something to a file every time it
gets called. But suppose create_new_log_file returns nil, due to some
mistake you've made while coding it. No exception is raised, so when
you run your program, it performs its job appropriately. You move on.

Two months later, you urgently need to get information from those
logs. But uh-oh - the log files are empty. Now you're screwed.

Bill

···

On 5/8/05, Lionel Thiry <lthiryidontwantspam@skynetnospam.be> wrote:

Cyent a écrit :
> I'm observing a general trend in the responses to RCR 303.
>
> The first and most striking is -w. I always, utterly and without fail, use
> -w and had assumed incorrectly that everyone else did. (But then I always
> use -W -Wall on gcc as well)
>

I suppose it's easier to refuse an RCR than to change programming habits.

--
Lionel Thiry

Personal website: http://users.skynet.be/lthiry/

--
Bill Atkins

You confirm what I am saying about the difference between "uninitialized and "no thing here". There should be an explicit difference.

Such a mistake you have presented would typically fill "file" with "uninitialized", and invoking the log method on "uninitialized" should throw an exception.

On the other hand, a nifty way of deliberately switching off logging, without changing a line of the client code would be to stuff "No thing here" into file, resulting in no thing happening.

That is why I have now withdrawn my RCR, and are working instead on an implementation of the Nothing class, leaving "nil" to mean "uninitialized".

It's coming along very nicely thank you, the only sorrow I have at the moment is to be able to do what I used to with nil takes a bit more typing....

   may_be_nothing = nil

   if may_be_nothing
     definitely_isnt_nothing( may_be_nothing)
   end

now becomes...

   may_be_nothing = Nothing.new # I love that
   unless may_be_nothing.nothing?
     definitely_isnt_nothing( may_be_nothing)
   end

ie. "nil" is a Special object in ruby, and the code for handling "if" statements knows about it. (The RTEST macro in ruby.h)

But hopefully the change conditional to virtual method refactoring will make most of those instances go away.

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Surprisingly enough, this email does not originate from a beetle.

···

On Mon, 9 May 2005, Bill Atkins wrote:

This isn't about changing programming habits. Having nil return nil
for missing methods can have serious consequences.

Consider:

  file = create_new_log_file
  file.log "here's a bit of information"

You're expecting this code to log something to a file every time it
gets called. But suppose create_new_log_file returns nil, due to some
mistake you've made while coding it.

Bill Atkins wrote:

This isn't about changing programming habits. Having nil return nil
for missing methods can have serious consequences.

Consider:

   file = create_new_log_file
   file.log "here's a bit of information"

You're expecting this code to log something to a file every time it
gets called. But suppose create_new_log_file returns nil, due to some
mistake you've made while coding it. No exception is raised, so when
you run your program, it performs its job appropriately. You move on.

Two months later, you urgently need to get information from those
logs. But uh-oh - the log files are empty. Now you're screwed.

When I see code samples arguing in favor of the status quo, I tend to think, But you only code it like that because you have certain expectations regarding nil.

And I think a good part of the argument for changing the current behavior is that, assuming one is cognizant of the new nil behavior, people will stop writing code that expects nil to yell at them. (Though that doesn't address legacy code. Ignore that for the moment.)

However, even assuming a magic wand that instantly grants each coder sparkling insight into the new behavior, I have a hard time seeing the overall benefit.

Given the above example, how would one code it with new-style nil?
Explicitly test for nil-ness? Too fugly.

Given Ruby's nature, one might have to test every object on every call, because who knows what might be touching it and inadvertently setting it to nil.

For more interesting and useful would be to solve the threading issue with using nil.blackhole = true inside of blocks or methods where that behavior is an overall win.

James

irb(main):001:0> file.log 'here is a bit of infromation'
NameError: undefined local variable or method `file' for main:Object
         from (irb):1
irb(main):002:0> file = nil
=> nil
irb(main):003:0> file.log 'here is a bit of infromation'
NoMethodError: undefined method `log' for nil:NilClass
         from (irb):3
irb(main):004:0>

···

On 05/09/2005 04:21 AM, Bill Atkins wrote:

This isn't about changing programming habits. Having nil return nil
for missing methods can have serious consequences.

Consider:

   file = create_new_log_file
   file.log "here's a bit of information"

You're expecting this code to log something to a file every time it
gets called. But suppose create_new_log_file returns nil, due to some
mistake you've made while coding it. No exception is raised, so when
you run your program, it performs its job appropriately. You move on.

Two months later, you urgently need to get information from those
logs. But uh-oh - the log files are empty. Now you're screwed.

--
Dr Balwinder Singh Dheeman Registered Linux User: #229709
CLLO (Chief Linux Learning Officer) Machines: #168573, 170593, 259192
Anu's Linux@HOME Distros: Ubuntu, Fedora, Knoppix
More: http://anu.homelinux.net/~bsd/ Visit: http://counter.li.org/

But Ruby already makes a distinction between nil and uninitialized. Compare:

    b + 4
    NameError: undefined local variable or method `b' for main:Object

with

    b = nil; b + 4
    NoMethodError: undefined method `+' for nil:NilClass

In my example, file is certainly initialized - it's just initialized
to nil. If create_new_log_file returns nil, file can't be considered
uninitialized.

···

On 5/8/05, John Carter <john.carter@tait.co.nz> wrote:

On Mon, 9 May 2005, Bill Atkins wrote:

> This isn't about changing programming habits. Having nil return nil
> for missing methods can have serious consequences.
>
> Consider:
>
> file = create_new_log_file
> file.log "here's a bit of information"
>
> You're expecting this code to log something to a file every time it
> gets called. But suppose create_new_log_file returns nil, due to some
> mistake you've made while coding it.

You confirm what I am saying about the difference between "uninitialized
and "no thing here". There should be an explicit difference.

Such a mistake you have presented would typically fill "file" with
"uninitialized", and invoking the log method on "uninitialized" should
throw an exception.

On the other hand, a nifty way of deliberately switching off logging,
without changing a line of the client code would be to stuff "No thing
here" into file, resulting in no thing happening.

That is why I have now withdrawn my RCR, and are working instead on an
implementation of the Nothing class, leaving "nil" to mean
"uninitialized".

It's coming along very nicely thank you, the only sorrow I have at the
moment is to be able to do what I used to with nil takes a bit more
typing....

   may_be_nothing = nil

   if may_be_nothing
     definitely_isnt_nothing( may_be_nothing)
   end

now becomes...

   may_be_nothing = Nothing.new # I love that
   unless may_be_nothing.nothing?
     definitely_isnt_nothing( may_be_nothing)
   end

ie. "nil" is a Special object in ruby, and the code for handling "if"
statements knows about it. (The RTEST macro in ruby.h)

But hopefully the change conditional to virtual method refactoring will
make most of those instances go away.

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Surprisingly enough, this email does not originate from a beetle.

--
Bill Atkins

Hi --

That is why I have now withdrawn my RCR, and are working instead on an implementation of the Nothing class, leaving "nil" to mean "uninitialized".

I'm not getting exactly what you mean by "mean". Do you mean there's
a convention of initializing variables to nil, prior to (say) their
use as iterator variables or counters? If so, that's very different
from an uninitialized variable.

Or do you mean instance variables and global variables, which evaluate
to nil by default prior to being initialized?

David

···

On Mon, 9 May 2005, John Carter wrote:

--
David A. Black
dblack@wobblini.net

James Britt schrieb:

Far more interesting and useful would be to solve the threading issue with using nil.blackhole = true inside of blocks or methods where that behavior is an overall win.

Could you describe the threading issue, maybe in form of some unit tests?

Regards,
Pit

What does that show?

···

On 5/9/05, Dr Balwinder S Dheeman <bsd.SANSPAM@cto.homelinux.net> wrote:

On 05/09/2005 04:21 AM, Bill Atkins wrote:
> This isn't about changing programming habits. Having nil return nil
> for missing methods can have serious consequences.
>
> Consider:
>
> file = create_new_log_file
> file.log "here's a bit of information"
>
> You're expecting this code to log something to a file every time it
> gets called. But suppose create_new_log_file returns nil, due to some
> mistake you've made while coding it. No exception is raised, so when
> you run your program, it performs its job appropriately. You move on.
>
> Two months later, you urgently need to get information from those
> logs. But uh-oh - the log files are empty. Now you're screwed.

irb(main):001:0> file.log 'here is a bit of infromation'
NameError: undefined local variable or method `file' for main:Object
         from (irb):1
irb(main):002:0> file = nil
=> nil
irb(main):003:0> file.log 'here is a bit of infromation'
NoMethodError: undefined method `log' for nil:NilClass
         from (irb):3
irb(main):004:0>

--
Dr Balwinder Singh Dheeman Registered Linux User: #229709
CLLO (Chief Linux Learning Officer) Machines: #168573, 170593, 259192
Anu's Linux@HOME Distros: Ubuntu, Fedora, Knoppix
More: http://anu.homelinux.net/~bsd/ Visit: http://counter.li.org/

--
Bill Atkins

Or do you mean instance variables and global variables, which evaluate
to nil by default prior to being initialized?

Well, that one is clearly a case of nil === "uninitialized"

Do you mean there's a convention of initializing variables to nil, prior to (say) their use as iterator variables or counters? If so, that's very different from an uninitialized variable.

Let me bounce that question back to you...

When _you_ personally do that, what do you mean? Do you mean "This is ruby's, umm, curious way of declaring local variables, namely by initializing them to something. I am initializing this local variable to nil. By this I, David A. Black mean (tick one)

   a) This local variable is uninitialized and I wish ruby to throw an
      error if I invoke a method on it before initializing it to
      something meaningful.

   b) This local variable holds "no thing", and doing nothing and
      returning nothing would be an appropriate action on invoking a
      method on it.

Myself, John Carter, would like on some occasions to tick one and on
other occasions to tick the other. Currently, whatever I mean, the
effect is a).

I can, and am currently writing a Nothing class that allows me to
assign NOTHING, the sole instance of my Nothing class to a local
variable in the case you describe.

But I'm running up against the gotcha that deep in "ruby.h" is a macro
RTEST.

Rubies interpretor, eval.c uses RTEST in many places. In "if",
in "unless", in "while", in....

RTEST is 0 (false) in the C speaking world of eval if an ruby
expression evaluates to false or nil.

For my Nothing class to really work well, I would need RTEST to
evaluate to 0 for nil,false and NOTHING.

All Work arounds and suggestions welcome...

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Surprisingly enough, this email does not originate from a beetle.

···

On Mon, 9 May 2005, David A. Black wrote:

Pit Capitain wrote:

James Britt schrieb:

Far more interesting and useful would be to solve the threading issue with using nil.blackhole = true inside of blocks or methods where that behavior is an overall win.

Could you describe the threading issue, maybe in form of some unit tests?

If you change the behavior of NilClass (e.g., NilClass.blackhole = true) it is changed for all nil occurrences (nil is a singleton object, so there is only one instance).

If there are multiple threads running, and one of them decides NilClass should swallow all unknown methods (even if only during the execution of a specific block) then all processes will see the same behavior until some code sets NilClass.blackhole = false.

James

What does that show?

This isn't about changing programming habits. Having nil return nil
for missing methods can have serious consequences.

Consider:

  file = create_new_log_file
  file.log "here's a bit of information"

You're expecting this code to log something to a file every time it
gets called. But suppose create_new_log_file returns nil, due to some
mistake you've made while coding it. No exception is raised, so when
you run your program, it performs its job appropriately. You move on.

Two months later, you urgently need to get information from those
logs. But uh-oh - the log files are empty. Now you're screwed.

Why two months later? If your method 'create_new_log_file' returns nil, i.e saved in 'file', an exception 'NoMethodError' is raised for undefined method 'log' for nil:NilClass which clearly is 'file' in your example above.

What do you want to prove? otherwise?

···

On 05/09/2005 10:19 PM, Bill Atkins wrote:

On 5/9/05, Dr Balwinder S Dheeman <bsd.SANSPAM@cto.homelinux.net> wrote:

On 05/09/2005 04:21 AM, Bill Atkins wrote:

irb(main):001:0> file.log 'here is a bit of infromation'
NameError: undefined local variable or method `file' for main:Object
        from (irb):1
irb(main):002:0> file = nil
=> nil
irb(main):003:0> file.log 'here is a bit of infromation'
NoMethodError: undefined method `log' for nil:NilClass
        from (irb):3
irb(main):004:0>

--
Dr Balwinder Singh Dheeman Registered Linux User: #229709
CLLO (Chief Linux Learning Officer) Machines: #168573, 170593, 259192
Anu's Linux@HOME Distros: Ubuntu, Fedora, Knoppix
More: http://anu.homelinux.net/~bsd/ Visit: http://counter.li.org/

As I pointed out, Ruby already handles unitialized variables as a
separate case. Ruby makes a distinction between uninitialized and
initialized variables. Just because a variable happens to be set to
nil doesn't make that variable uninitialized.

···

On 5/8/05, John Carter <john.carter@tait.co.nz> wrote:

On Mon, 9 May 2005, David A. Black wrote:

> Or do you mean instance variables and global variables, which evaluate
> to nil by default prior to being initialized?

Well, that one is clearly a case of nil === "uninitialized"

> Do you mean there's a convention of initializing variables to nil, prior
> to (say) their use as iterator variables or counters? If so, that's
> very different from an uninitialized variable.

Let me bounce that question back to you...

When _you_ personally do that, what do you mean? Do you mean
"This is ruby's, umm, curious way of declaring local variables, namely by
initializing them to something. I am initializing this local variable to
nil. By this I, David A. Black mean (tick one)

   a) This local variable is uninitialized and I wish ruby to throw an
      error if I invoke a method on it before initializing it to
      something meaningful.

   b) This local variable holds "no thing", and doing nothing and
      returning nothing would be an appropriate action on invoking a
      method on it.

Myself, John Carter, would like on some occasions to tick one and on
other occasions to tick the other. Currently, whatever I mean, the
effect is a).

I can, and am currently writing a Nothing class that allows me to
assign NOTHING, the sole instance of my Nothing class to a local
variable in the case you describe.

But I'm running up against the gotcha that deep in "ruby.h" is a macro
RTEST.

Rubies interpretor, eval.c uses RTEST in many places. In "if",
in "unless", in "while", in....

RTEST is 0 (false) in the C speaking world of eval if an ruby
expression evaluates to false or nil.

For my Nothing class to really work well, I would need RTEST to
evaluate to 0 for nil,false and NOTHING.

All Work arounds and suggestions welcome...

John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john.carter@tait.co.nz
New Zealand

Surprisingly enough, this email does not originate from a beetle.

--
Bill Atkins

Hi --

Do you mean there's a convention of initializing variables to nil, prior to (say) their use as iterator variables or counters? If so, that's very different from an uninitialized variable.

Let me bounce that question back to you...

When _you_ personally do that, what do you mean? Do you mean "This is ruby's, umm, curious way of declaring local variables, namely by initializing them to something. I am initializing this local variable to nil. By this I, David A. Black mean (tick one)

a) This local variable is uninitialized and I wish ruby to throw an

Clearly I can't regard it as uninitialized, if I've just initialized
it.

    error if I invoke a method on it before initializing it to
    something meaningful.

You can't initialize a variable twice. The second time around it's
just "assignment" :slight_smile:

[...]

I can, and am currently writing a Nothing class that allows me to
assign NOTHING, the sole instance of my Nothing class to a local
variable in the case you describe.

I understand the goal of your project; I only mean to encourage you to
start from the clearest possible understanding of what the language
does -- specifically, that variables you have initialized to nil are
not uninitialized. If you use the term "uninitialized" to describe
the x in "x = nil", I think snags in terminology and/or logic may
follow later on.

David

···

On Mon, 9 May 2005, John Carter wrote:

On Mon, 9 May 2005, David A. Black wrote:

--
David A. Black
dblack@wobblini.net