No Thing Here vs Uninitialized and RCR 303

C

Cyent

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 - (e-mail address removed)

http://geocities.yahoo.com/cy_ent

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.
 
C

Christoph

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::)

/Christoph
 
D

David A. Black

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 :)
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
 
J

James Britt

Cyent said:
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
 
G

Gavin Kistner

--Apple-Mail-1--182650989
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
delsp=yes;
format=flowed

On May 8, 2005, at 1:04 AM, Cyent wrote:
[...]
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.
--Apple-Mail-1--182650989--
 
J

James Britt

Christoph said:
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::)

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] http://www.ecma-international.org/publications/standards/Ecma-262.htm
[1] http://www.ecma-international.org/news/4xpr-final-2004.htm

--

http://www.ruby-doc.org
http://www.rubyxml.com
http://catapult.rubyforge.com
http://orbjson.rubyforge.com
http://ooo4r.rubyforge.com
http://www.jamesbritt.com
 
L

Lionel Thiry

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.
 
B

Bill Atkins

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
 
J

John Carter

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 : (e-mail address removed)
New Zealand


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

James Britt

Bill said:
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
 
B

Bill Atkins

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.
 
D

David A. Black

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
 
J

John Carter

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 : (e-mail address removed)
New Zealand


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

Bill Atkins

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.
 
P

Pit Capitain

James said:
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
 
D

David A. Black

Hi --

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" :)

[...]
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
 
J

James Britt

Pit said:
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
 
B

Bill Atkins

What does that show?

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/
 
M

mark sparshatt

Dr said:
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?
I think the point that Bill Atkins is trying to make is that if RCR 303
is accepted then an exception won't be raised, and so he won't discover
the error till he actually looks at the log file.
 
P

Pit Capitain

James said:
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.

I don't know whether this would be useful, but you can use thread-local
variables [1] to make this behavior dependent on the current thread. I
can send you the code, if you like.

Constraining this behavior to a specific block is more interesting. Do
you think of lexical or dynamic scope? (With "lexical scope" I mean only
the code in a given block, whereas "dynamic scope" would be the code in
the block plus all methods called from there.)

Regards,
Pit

[1] http://www.ruby-doc.org/core/classes/Thread.html#M001024
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top