Not only does this simplify ruby programs considerably, it also
changes certain crash bugs silently into correct programs.
If you were to investigate most cases where an if statement checks to
see if a value is non-nil, you will find that the else clause is
empty. ie. Does nothing.
I expect if this is accepted to see a bunch of knock on RCR's, namely
nil+n == n
nil * 7 == 0
-nil == 0
We already have
nil.to_s == ""
nil.to_i == 0
nil.to_f == 0.0
Doing an informal subsampling of the standard libs, I can see no
instances where this change will cause a problem, several cases where
this change could substantially simplify code, and several cases where
this change would result in The Right Thing happening instead of a
crash if the routine was fed a nil.
John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john....@tait.co.nz
New Zealand
Somewhere on the edge of a Galaxy, one of literally billions of such
galaxies, is a sun, one of literally billions of suns in that
galaxy.
Orbiting that sun is a small rock 330000 times smaller than that
sun.
This rock is covered by a very very thin scum of life. (Think 6000km
of rock followed by a meter or so of biomass.)
Amongst the millions of species in that scum are many hundreds of
thousands of types beetle and a mere handful of primates.
Surprisingly enough, this email does not originate from a beetle.
It originates from just one of the 6 billion vastly outnumbered humans.
I trust you will keep this perspective and context in mind when
reacting to this email.
This would be a big change to behaviour and a lot of existing programs
could have problems with it. Because integers already have a to_i(),
its possible to do this...
x.to_i + 3
and have it do what you want.
--
spooq
I'll comment also.
First of all, I sympathize on some level with this RCR. It has
been thought of before, by me and others.
In fact, I *think* that this was Ruby's default behavior once upon
a time; and I think it was changed for a good reason(s) I don't recall.
In other words, I think it falls under the category of "things that
were already in and have been taken out" (like Object#to_a, and like
the 'end' suffixes -- end if, end while, etc., which were taken out
when modifiers like 'x if y' were added).
FWIW, if x has a to_int, even this should work:
y = 3 + x
although
y = x + 3
wouldn't. But that is neither here nor there. And if something is
neither here nor there, where is it??
Hal
> John Carter wrote:
>
>> A very simple and generic way of improving the reliability of Ruby
>> programs is to implement the NullObject pattern by allowing nil to
>> accept all and every method instead of throwing a NoMethodError.
>
> I, for one, would rather see it throwing an error as it is now. Dead programs
> don't tell lies.
I would suggest next 5 times you have a nil class throws
NoMethodError crash, just add this at the head of your program...
class NilClass
def method_missing( sym, *args)
nil
end
end
And see what happens.
If, your program then works correctly, then I am right.
If, your still program thows an exception or reports an error, but perhaps
a slightly different point, then I am still right, namely this change
doesn't hide bugs.
If the program silent proceeds to do the wrong thing, then I am wrong.
I ask members of this list to actually try this experiment the next couple
of times they hit a nil throws NoMethodError and send the results to me.
I will summarize to the list.
If I prove wrong, I will gladly retract my RCR and apologise.
John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john....@tait.co.nz
New Zealand
This rock is covered by a very very thin layer of life. (Think 6000km
> On 5/6/05, John Carter <john....@tait.co.nz> wrote:
>> I expect if this is accepted to see a bunch of knock on RCR's, namely
>> nil+n == n
>> nil * 7 == 0
>> -nil == 0
>>
>> We already have
>> nil.to_s == ""
>> nil.to_i == 0
>> nil.to_f == 0.0
>
> This would be a big change to behaviour and a lot of existing programs
> could have problems with it. Because integers already have a to_i(),
> its possible to do this...
If there were a lot of programs deliberately doing
begin
# some complex calculation
rescue NoMethodError => details
# Do some valid functionality, not just error handling
end
I would agree with out.
If they are not doing that, then the program would
just crash totally. My change would change the behaviour from crashing, to
Doing The Right thing.
But I don't believe that there are programs rescuing NoMethodErrors/
I bet you could search they whole RAA and find very very little that has
rescue NoMethodError.
John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john....@tait.co.nz
New Zealand
This rock is covered by a very very thin scum of life. (Think 6000km
> On Fri, 6 May 2005, Alexey Verkhovsky wrote:
>
>> John Carter wrote:
>>
>>> A very simple and generic way of improving the reliability of Ruby
>>> programs is to implement the NullObject pattern by allowing nil to
>>> accept all and every method instead of throwing a NoMethodError.
>>
>> I, for one, would rather see it throwing an error as it is now. Dead
>> programs don't tell lies.
>
> I would suggest next 5 times you have a nil class throws NoMethodError
> crash, just add this at the head of your program...
>
> class NilClass
> def method_missing( sym, *args)
> nil
> end
> end
I think that any RCR than can be implemented in pure ruby doesn't need
to go into the core. You can place a package on RAA and get a project
on RubyForge for these kinds of things handily.
--
Eric Hodel - drb...@segment7.net - http://segment7.net
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04
Only if the right thing is "do not crash ever".
For me, if a bug like that is exposed, _it's a severe error_. Not
something to say is nil.
> First of all, I sympathize on some level with this RCR. It has
> been thought of before, by me and others.
>
> In fact, I *think* that this was Ruby's default behavior once upon
> a time; and I think it was changed for a good reason(s) I don't recall.
Be careful about exactly what is being asked for and what has been done
before. I once developed an OOP system were all objects would respond to
all undefined messages by doing nothing. I rapidly changed that to an
error condition as in that case the complaint that it hid bugs was valid.
What I'm asking for here is that just the nil object, not even the false
object, responds to all undefined methods by doing nothing and returning
nil.
John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john....@tait.co.nz
New Zealand
Ive got to agree with this - sometimes crashing really is the best
thing to do. Thats the point of assertions, for example. It certainly
gets attention. Getting a nil back when you expect a real value is a
pretty good sign something is wrong and really shouldnt be treated
lightly.
--
spooq
> I think that any RCR than can be implemented in pure ruby doesn't need to go
> into the core. You can place a package on RAA and get a project on RubyForge
> for these kinds of things handily.
I agree with you in general, but not in this particular instance.
A scripting language like ruby is partly about cleanliness and brevity of
expression. By making it part of the core, it permits even oneliners to
use the simplicity it gives.
Since it does change NilClass, although I don't believe it breaks any
existing code, it then makes a firm declaration that you can rely on any
future system and RAA libraries not to break.
As I say, I'm willing to be proven wrong.
John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john....@tait.co.nz
New Zealand
Somewhere on the edge of a Galaxy, one of literally billions of such
galaxies, is a sun, one of literally billions of suns in that
galaxy.
Orbiting that sun is a small rock 330000 times smaller than that
sun.
This rock is covered by a very very thin scum of life. (Think 6000km
of rock followed by a meter or so of biomass.)
Amongst the millions of species in that scum are many hundreds of
Right. But why should I have to make that change for just about any
application that I end up writing? There are a lot of cases where
nil can arise -- and if it does arise, it may be incorrect. Do you
*want* to give me RSI by forcing me to do:
foo.bar unless foo.nil?
Sorry, but the current behaviour is more correct.
> What I'm asking for here is that just the nil object, not even
> the false object, responds to all undefined methods by doing
> nothing and returning nil.
But nil isn't an Anything object, it's nothing. It shouldn't respond
to things that it doesn't know about.
If you want nil as a null object, use a module to extend the
behaviour -- but don't be surprised if a lot of programs start dying
for unclear reasons.
-austin
--
Austin Ziegler * halos...@gmail.com
* Alternate: aus...@halostatue.ca
> But nil isn't an Anything object, it's nothing. It shouldn't respond
> to things that it doesn't know about.
Ah, but you're wrong, nil is "no thing, of any type, is here."
> If you want nil as a null object, use a module to extend the
> behaviour -- but don't be surprised if a lot of programs start dying
> for unclear reasons.
Prove me wrong, take the challenge.
Next time your pet program dies of a NoMethodError for NilClass add
class NilClass
def method_missing(sym,*args)
nil
end
end
..at the head of your program.
See empirically what happens. Does it hide bugs? Does it just work? Does
it still throw an exception or give an error message?
Try this next few occasions you get such a bug, each time email me the
results, I will summarize to the group.
John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john....@tait.co.nz
New Zealand
Is it? Prove me wrong empirically...
Save this code as nillit.rb
class NilClass
def method_missing( symbol, *args)
nil
end
end
Next time your program crashes on a "undefined method `foo' for
nil:NilClass (NoMethodError)"
Rerun your code with....
ruby -rnillit myprog
and see what happens, tell me the result. I'm prepared to be proven wrong.
John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john....@tait.co.nz
New Zealand
Amongst the millions of species are many hundreds of
thousands of types beetle and a mere handful of primates.
Surprisingly enough, this email does not originate from a beetle.
I don't like it. It would hide many bugs. I want Ruby to throw an
exception when I'm ending up with something like that:
some_var = some_method
# some_method *should* return an IO object, but this time
# it returned nil
some_var.puts "important data"
It would be horribly if Ruby didn't throw an exception.
Stefan
John wants to be proven wrong with real code. (Well, Im sure he doesnt
-want- to be proven wrong, but you know...). I can think of some
artificial code that proves the point, but Im not sure its fair to
post it.
--
spooq
In message "Re: RCR 303: nil should accept missing methods and return nil"
on Fri, 6 May 2005 12:51:00 +0900, John Carter <john....@tait.co.nz> writes:
|Be careful about exactly what is being asked for and what has been done
|before. I once developed an OOP system were all objects would respond to
|all undefined messages by doing nothing. I rapidly changed that to an
|error condition as in that case the complaint that it hid bugs was valid.
I know Objective-C's nil works like that. I once developed an OOP
system (which was an early version of Ruby) where nil would respond to
all undefined messages by doing nothing. In production code, it does
nothing bad, since any production code should not raise an exception.
Rather it introduces new scheme of error handling.
But during development, it can hide bugs. It is very difficult to
distinguish correct error handling by ignoring unknown message, and
uncontrolled unintentional misbehavior caused by bugs. It's against
the principle of "early death".
Your proposal worth something, I think. But it's not going to be seen
in the near future of Ruby.
matz.
I'm sorry, is this some kind of hoax? A program will not magically be
correct simply because an error is hidden. Think of all the subtle bugs
this would introduce, for example: you create an array with a fixed number
of elements and forget to give the default value 55. Now math would work,
but the results would be wrong - and you might not even catch this.
The article at
http://www.smalltalkchronicles.net/edition2-1/null_object_pattern.htm that
you refer to in the RCR states, that it's a bad idea to introduce this
change in Smalltalk because it would break too much code. The situation in
Ruby is similar.
> If you were to investigate most cases where an if statement checks to
> see if a value is non-nil, you will find that the else clause is
> empty. ie. Does nothing.
But that would only work in cases like
unless x.nil?
x.do_something
end
i.e. where the block invokes methods on nil. This could be safely
transferred to
x.do_something
with your approach. But other cases cannot.
Regards
robert
I'm sorry, is this some kind of hoax? A program will not magically be
correct simply because an error is hidden. Think of all the subtle bugs
this would introduce, for example: you create an array with a fixed number
of elements and forget to give the default value 55. Now math would work,
but the results would be wrong - and you might not even catch this.
The article at
http://www.smalltalkchronicles.net/edition2-1/null_object_pattern.htm that
you refer to in the RCR states, that it's a bad idea to introduce this
change in Smalltalk because it would break too much code. The situation in
Ruby is similar.
> If you were to investigate most cases where an if statement checks to
> see if a value is non-nil, you will find that the else clause is
> empty. ie. Does nothing.
But that would only work in cases like
On Fri, 6 May 2005, Eric Hodel wrote:
> I think that any RCR than can be implemented in pure ruby doesn't need to go
> into the core. You can place a package on RAA and get a project on RubyForge
> for these kinds of things handily.
I disagree. For one thing, there are real issues with modifying core
classes and methods; it's not a safe fallback. Also, most of Ruby can
be implemented in pure Ruby -- and some of what's in Ruby started life
as RCRs, either formal or informal. So you'd be creating an odd
situation: Matz will make changes that can be implemented in pure
Ruby, but no one else should suggest or discuss such changes.
I don't think there's any sign that that's what Matz has in mind with
the RCR process.
David
--
David A. Black
dbl...@wobblini.net
Actually, it is the current behavior that forces you to write the "unless
foo.nil?", since sending the "bar" message to nil is an error. If nil was
changed to be a message eating variant, then
foo.bar
and
foo.bar unless foo.nil?
would be equivalent. In other words, the change would help alleviate your RSI
problems.
I will admit that my gut reaction is to fall in the "should throw an
exception" camp. But the idea of a universal Null Design Pattern with nil is
intriguing. John's suggested experiment is fairly painless ... I'm willing
to try it and see if I'm persuaded.
--
-- Jim Weirich j...@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
perhaps
nil.blackhole = true
to change nil's behaviour. that way it could be changed in production code?
-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| renunciation is not getting rid of the things of this world, but accepting
| that they pass away. --aitken roshi
===============================================================================
But, if foo wasn't supposed to be nil, what would happen? foo.bar gives nil,
which would be used by other operations that each would give nil, nil, and nil
again. And at the end of the chain, you don't have your expected behavior,
because there was a bug. From where did the first unwanted nil come from? Where
is that bug?
Then, to prevent such annoying bug to happen, I suppose I'd feel forced to write
this each time I suspect some foo could be nil:
if $debug && foo.nil?
raise "foo is nil"
else
foo.bar
end
My opinion is that: nil handling is annoying but difficult debuging is worse.
>
> I will admit that my gut reaction is to fall in the "should throw an
> exception" camp. But the idea of a universal Null Design Pattern with nil is
> intriguing. John's suggested experiment is fairly painless ... I'm willing
> to try it and see if I'm persuaded.
>
If the initial goal of this RCR is to make the Null Design Pattern somewhat
universal in ruby, what about having a new litteral like for example
"null_object" that would do that job?
--
Lionel Thiry
Personal website: http://users.skynet.be/lthiry/
Well, there is already $DEBUG. I think that should work fine, in case
this proposal were accepted.
> -a
E
--
template<typename duck>
void quack(duck& d) { d.quack(); }
not at all - $DEBUG would need to be on by defualt then and most of the time
then and this causes reams of output on STDERR for many libs in addition to
subtly changing their behaviour.
what i'm suggesting is a 'normal' behaviour whereby nil throws NoMethodError
(current default) - note that this is NOT $DEBUG=true - and a built-in swith
to turn it off
nil.blackhole = true
or perhaps a new global
$NIL_BLACKHOLE = true
or maybe better
NilClass::blackhole = true
to cause nil to obey the null pattern.
this feature wouldn't affect any code now since the normal behaviour would
remain the same. $DEBUG is a global that affects tons of code in addition to
the (proposed) nil mods and therefore can't be used i think.
cheers.
Wouldn't it be even simpler to include the proposed nillify.rb in the
standard and use either
require 'nillify' or
ruby -rnillify.
Or even simpler, just include the declaration in the program?
regards,
Brian
--
http://ruby.brian-schroeder.de/
multilingual _non rails_ ruby based vocabulary trainer:
http://www.vocabulaire.org/ | http://www.gloser.org/ | http://www.vokabeln.net/
No. I can tell you from experience over the last four days that I
have fixed no fewer than five *real* bugs in PDF::Writer that would
have resulted in the incorrect generation of PDF output had I done
this. Probably even created a PDF that would crash any PDF reader
out there.
> If, your program then works correctly, then I am right.
This will happen in only a few applications; I would argue it will
never happen in anything that has to communicate with the outside
world.
> If, your still program thows an exception or reports an error, but
> perhaps a slightly different point, then I am still right, namely
> this change doesn't hide bugs.
Yes, it does, at least with PDF::Writer. The output for PDF has to
be correct. And in this case, PDF::Writer would simply do the wrong
thing.
> If they are not doing that, then the program would just crash
> totally. My change would change the behaviour from crashing, to
> Doing The Right thing.
Um. I think that the point being made is that crashing, in this
case, *is* doing the right thing. If nil respondedd to all methods
silently, how would you ever know when your method got the *wrong*
data?
I said this on the RCR comment area, but PDF::Writer is *correct* to
blow up when it gets nil. Without this, there are things that I
could not *possibly* have debugged. With the silent eating of
messages, the generated PDF files would be incorrect -- invalid --
and there's not a damned thing I could do to tell where the problem
is.
I don't really know what to say to this -- this will turn a correct
behaviour into a completely invalid behaviour.
>> foo.bar unless foo.nil?
>> Sorry, but the current behaviour is more correct.
> Actually, it is the current behavior that forces you to write the
> "unless foo.nil?", since sending the "bar" message to nil is an
> error.
Not really. The precise example I gave is a bad one. But generally,
if I'm calling #do_something, it's because I want something done. If
I have a nil object instead, then I have a problem -- and I want to
know it as early as possible.
I've emphasized this in both fora, but there have been some problems
during the redevelopment of PDF::Writer that *would* have been
masked by this sort of behaviour, resulting in bad output. If I had
this, then I would have to comb through the bad output to find the
problem. This is difficult when the fault might be literally
hundreds (or thousands) of lines away from what generates the error.
If I say #do_something and have a nil object, this proposal merely
masks the problem -- that I got a nil object to operate on. If what
I'm using is never supposed to return nil, but did anyway, this is
definitely wrong.
(And yes, I have had *exactly this problem*. No, I can't show you
the code -- I fixed the problem and the code doesn't exist anywhere
at this point.)
For a very small class of problems, this will work. For anything
that has to interact outside of the Ruby program in question, this
is -- and always will be -- a disaster.
A simple example of "wrong" behavior (using the nil returns of !
methods which is another can of worms :-)
class NilClass
def method_missing(sym, *args)
nil
end
end
x = "Pat"
x.strip!.upcase!
#use x in some important way....
# this now fails silently, the expectation
# was for an upcased string with no "extra" white space....
puts x
As I mentioned before, I'm in the "throw an exception" camp. But the
argument that it will be a "disaster" sounds like the type of arguement a
static typer levels againts dynamic languages. So, I'm open to an
experiment.
And the first opportunty came up today. I am revising some command line
scripts that access a database. You have to specify an environment so
that the proper database case be choson. I forgot to specify the
environment and got:
$ ruby -Ilib bin/info.rb r887
lib/ics/folderid.rb:83:in `translate_rids': undefined method `sql' for
nil (NameError)
Then I added the -rnilify argument...
$ ruby -rnilify -Ilib bin/info.rb r887
Can't find folder for ID r887
So, adding in a message eating nil causes the script to think it can't
find the appropriate folder. While true, it is certainly not the best
error message that could be produced. I would imagine that tracing down
the source of this error would be more difficult than the other message. I
knew exactly what the problem was when I saw the NameError. The "can't
find" error leaves plenty of room for other possibilities.
So, at first blush, I'm still in the "throw an exception" camp.
On a side note, this whole discussion inspired me to solve the problem in
an interesting way. I just make sure I initialize the database object
with an instance of the following class:
class MissingDatabase
def method_missing(sym, *args, &block)
fail "No Database Specified"
end
end
> On a side note, this whole discussion inspired me to solve the problem in
> an interesting way. I just make sure I initialize the database object
> with an instance of the following class:
>
> class MissingDatabase
> def method_missing(sym, *args, &block)
> fail "No Database Specified"
> end
> end
Very nice! Some elaboration:
$ cat missing_obj.rb
class MissingObject < StandardError
def initialize(comment="")
@comment = comment
@location = caller[0][/.*?:\d+/]
end
def method_missing(meth, *args, &block)
raise self, "#{@location}: #{@comment}"
end
end
class MissingDatabase < MissingObject; end
def get_db_from_user_input
end
# Using nil:
my_db = get_db_from_user_input()
begin
my_db.lookup("foo")
rescue => e
p e
end
# Using a MissingObject
my_db = get_db_from_user_input() ||
MissingDatabase.new("No user input")
begin
my_db.lookup("foo")
rescue => e
p e
end
$ ruby missing_obj.rb
#<NoMethodError: undefined method `lookup' for nil:NilClass>
#<MissingDatabase: missing_obj.rb:26: No user input>
Actually, throwing an exception might be better to do at an earlier
point. Essentially two types of nils exists; the expected ones and
the unexpected ones, of which the latter cause the problems here.
Most of these problems could be 'avoided', however, if instead
of returning nil, an exception were thrown.
>On a side note, this whole discussion inspired me to solve the problem in
>an interesting way. I just make sure I initialize the database object
>with an instance of the following class:
>
> class MissingDatabase
> def method_missing(sym, *args, &block)
> fail "No Database Specified"
> end
> end
>--
>-- Jim Weirich j...@weirichhouse.org http://onestepback.org
E
> A very simple and generic way of improving the reliability of Ruby
> programs is to implement the NullObject pattern by allowing nil to
> accept all and every method instead of throwing a NoMethodError.
Great! I've so long waited for something like this. I have just written
a very reliable program, with this new feature:
class NilClass
def method_missing(*ignore) nil end
end
class Counter
def initialize
@count = 1
end
attr_reader :count
def increase
@count += 1
end
end
class DoSomething
def initialize
@coutner = Counter.new
end
def count_done
@counter.count
end
def do_it
@counter.increase
end
end
ds = DoSomething.new
10.times do
ds.do_it
end
puts "Have done it #{ds.count_done} times."
--
Florian Frank
Ah, but _would_ it. On any other object I would agree with you. But nil
occupies a special place in the ruby world.
Also, Ruby is a dynamic language, with objects all the way down.
nil means in effect, no thing is here.
What happens if I tell no thing to do something.
No thing happens and I'm left with no thing.
So I ask you, next time you are working on your code, when you hit and
undefine method on nil, NoMethodError. Do my little trick.
Put...
class NilClass
def method_missing(sym,*args)
nil
end
end
in a file nillit.rb, and pull that file into your code with
ruby -w -rnillit your_code
See what happens.
Is your assertion correct?
Do you actually generate incorrect PDF? (In which case you are right)
Does it just plain work? (In which case I am right)
Or does it blow up with an exception or error report somewhen else? (I
which case I'm still right.)
Whatever happens, try it, and what ever the answer, email me or add a
comment to the RCR and I will summarize to the list later.
I'm better a beer (to be collected in Christchurch New Zealand) that
practical software will find that...
a) Mostly it will just do the right thing.
b) Otherwise it will do the right thing for now, and be caught later as an
Exception or error report. (I suspect by adding a few more things like
class NilClass
def respond_to?( sym)
true
end
end
may cure some of those...
c) And very rarely, far more rarely than people suspect, will it silently
do the wrong thing.
Also as you go along, consider cases where you could just drop
conditionals. How many if branches would you be quietly dropping?
As for debugging, if you look at the RCR, the implementation I give
creates state on nil that records which method was missing and in which
calling context.
--
John Carter
The Cybernetic Entomologist - cy...@xtra.co.nz
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.
Always look on the bright side of life...
(I mean - what have you got to lose?)
(You know, you come from nothing - you're going back to nothing.
What have you lost? Nothing!)
Always look on the right side of life...
Now maybe that's an argument for Python to adopt this RCR!
(Apologies to Eric Idle.)
> John Carter wrote:
>
>> A very simple and generic way of improving the reliability of Ruby
>> programs is to implement the NullObject pattern by allowing nil to
>> accept all and every method instead of throwing a NoMethodError.
>
> Great! I've so long waited for something like this. I have just written
> a very reliable program, with this new feature:
I presume the typo on @coutner was deliberate for illustrative purposes...
Unfortunately rubies run time switches are bug compatible with perl's.
If you read "man perl" and scroll down to the BUGS sections it says...
BUGS
The -w switch is not mandatory.
Anybody who is vaguely worried about bugs in their code whether they are
running perl or ruby should _always_ use the -w switch.
ruby -w frank.rb
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:29: warning: instance variable @counter not initialized
frank.rb:25: warning: instance variable @counter not initialized
Have done it times.
>
> I'm sorry, is this some kind of hoax? A program will not magically be
> correct simply because an error is hidden. Think of all the subtle bugs
> this would introduce, for example: you create an array with a fixed number
> of elements and forget to give the default value 55. Now math would work,
> but the results would be wrong - and you might not even catch this.
Think of an array with 42 elements. Access element 55. It returns nil. How
is this different?
If you think through the default values for arithmetic operations on nil
properly. My guess is the results in most case will be right.(How often do
you initialize an array to 55? 99.9% of the time you expect it to be full
of 0 or maybe 1.
How about nil autoconverts to the identity element for all operations. ie.
0 for +, 1 for *, "" for string concat.
In which case more code simplification, more code that just works.
> The article at
> http://www.smalltalkchronicles.net/edition2-1/null_object_pattern.htm that
> you refer to in the RCR states, that it's a bad idea to introduce this
> change in Smalltalk because it would break too much code. The situation in
> Ruby is similar.
Is it?
I wwnt grepping through ruby 1.9 CVS (ok its a month or two old version)
looking for some code that will break.
I don't believe _anything_ will (currently) break.
That's not a failure, thats a confirmation.
You asked for an upcase string with no whitespace. You have got one.
Wheres the problem?
You didn't ask for a non-empty string...
>Unfortunately rubies run time switches are bug compatible with perl's.
>
>
But unlike Perl, Ruby doesn't require warning switches to gloss over bad
decisions in its design process. We shouldn't make these in Ruby after
the fact, should we?
I never use warning switches in Ruby without having any adverse affects
from it. I wouldn't advice anyone to do that in Perl. In Perl these
switches are a real plague, especially because of false alarms: That
explains the invention of the "use warnings" and "no warnings" pragmas.
One question, I have left: Why do you hate Ruby so much?
--
Florian Frank
> If you read "man perl" and scroll down to the BUGS sections it
> says...
I fail to see why you're comparing the two, when perl's use of "-w" and
"use warnings" as a pragma, are different to how Ruby handles such
things.
> BUGS
> The -w switch is not mandatory.
>
> Anybody who is vaguely worried about bugs in their code whether they
> are
> running perl or ruby should _always_ use the -w switch.
As a guide, perhaps, but not because their program _might_ break -
that's why UnitTest is such a good thing to use.
-- Thomas Adam
"The Linux Weekend Mechanic" -- http://linuxgazette.net
"TAG Editor" -- http://linuxgazette.net
"<shrug> We'll just save up your sins, Thomas, and punish
you for all of them at once when you get better. The
experience will probably kill you. :)"
-- Benjamin A. Okopnik (Linux Gazette Technical Editor)
___________________________________________________________
Yahoo! Messenger - want a free and easy way to contact your friends online? http://uk.messenger.yahoo.com
Now there's a role model. I'd love to be like him,
just on the other side of the Atlantic. A sort of
American Idle.
Hal
Not really.
> nil means in effect, no thing is here.
And, if I'm expecting that some thing will be there, then I have an
error condition. Putting your nileater mechanism in place will
simply *mask* that I have a very real and very serious error. It
will also cause me to output incorrect information to my PDF files.
> What happens if I tell no thing to do something.
> No thing happens and I'm left with no thing.
You may, however, be left with incorrect output.
"\n#{@oid} 0 obj\n<</Type /Page /Parent #{@owner.oid} 0 R >>"
If @owner is nil, then using your proposal I will get:
234 0 obj
<</Type /Page /Parent 0 R >>
This is INCORRECT. This will, AT BEST, cause the page you're looking
at in a PDF reader to be partially or completely not rendered.
Equally likely, it will cause your PDF reader to crash. (Object
references are ALWAYS "id version R" in PDF.)
However, since I know that @owner should never be nil, when that
line blows up during execution, I can start tracing it from the blow
up. I can find out where and why @owner becomes nil and I can fix
it. Without the fatal error, I am left with a mysteriously crashing
PDF document -- and almost no debugging possible from a PDF reader.
This is real code, John. It's a bit simplified from the real case
(the real case is about 20 lines long and contains a lot more).
Indeed, I don't even need to go that far:
arr.empty?
This doesn't return +true+ if arr is +nil+. This means that
carefully crafted logic will, in fact, break.
(It also ignores the fact that nil *can* be a useful value.)
> Is your assertion correct?
Yes, John, it's correct. I know this without taking your challenge.
> Do you actually generate incorrect PDF? (In which case you are right)
Yes, I'm right. I know this without taking your challenge.
> Does it just plain work? (In which case I am right)
No, it doesn't. Never has, never will. I know this without taking
your challenge.
> Or does it blow up with an exception or error report somewhen
> else? (I which case I'm still right.)
You're not right. I know this without taking your challenge.
> I'm better a beer (to be collected in Christchurch New Zealand)
> that practical software will find that...
> a) Mostly it will just do the right thing.
This will be true so long as the program does not interact with
other programs that require strict conformance to output (or input!)
formats.
> b) Otherwise it will do the right thing for now, and be caught later as an
> Exception or error report. (I suspect by adding a few more things like
> class NilClass
> def respond_to?( sym)
> true
> end
> end
> may cure some of those...
Not in the case where you have to have strict conformance to data
formats. Not when you're dealing with numbers. What is 2 + nil? Is
it 2 or nil?
> c) And very rarely, far more rarely than people suspect, will it
> silently do the wrong thing.
Far more often.
> Also as you go along, consider cases where you could just drop
> conditionals. How many if branches would you be quietly dropping?
Well, strictly speaking, I *don't* have a branch now. I simply
assume that @owner is set and is set properly. If it isn't, I have a
serious error -- and no amount of pretending that this will work
will change that incorrect data will be output.
> As for debugging, if you look at the RCR, the implementation I
> give creates state on nil that records which method was missing
> and in which calling context.
Still won't help with the case where the error is in the generated
code (that is quite large and hard to read) -- it's very
disconnected from the real error.
A CGI script I coded a couple weeks ago just got:
[Fri May 06 20:22:37 PDT 2005] Process 27695 encountered
#<NoMethodError: undefined method `[]' for nil:NilClass>
at /var/www/---------.net/www/quake/servers/list.cgi:133:in `top_client'
and indeed, when I added method_missing to NilClass the bug
was masked and the script executed without complaint.
Interesting . . .
The bug was something in an as-yet untested "else" case
in the code. Something a unit test should have caught,
if i'd written any for this quick hack..... which I didn't.
I would count myself in the "fail as early as possible"
camp. I still don't like that NilClass#method_missing
masks the bug... but it did prevent the error in this
case from the user's point of view.
If I were to consider adding NilClass#method_missing
permanently to my script(s), I would at least cause it
to write the problem and stack trace to a logfile, so
that I could periodically scan the logfile for any such
incidents.
Interesting challenge though, thanks ... :)
Regards,
Bill
It's not different. But it's not an argument in favor of your suggestion
either.
> If you think through the default values for arithmetic operations on nil
> properly. My guess is the results in most case will be right.(How often do
> you initialize an array to 55? 99.9% of the time you expect it to be full
> of 0 or maybe 1.
>
> How about nil autoconverts to the identity element for all operations. ie.
> 0 for +, 1 for *, "" for string concat.
Not feasible since you would need a custom version of #coerce also and in
that method you don't know the operator (+ or * for example) - at least not
with standard means. And I would not like to see these perlish dirty tricks
in ruby.
> In which case more code simplification, more code that just works.
If you would drop this "code that just works" maybe I could find something
useful in your suggestion. I'm sorry, but I get the impression that you
don't really seem to overlook the effects of your suggestion.
>> The article at
>> http://www.smalltalkchronicles.net/edition2-1/null_object_pattern.htm
>> that
>> you refer to in the RCR states, that it's a bad idea to introduce this
>> change in Smalltalk because it would break too much code. The situation
>> in
>> Ruby is similar.
>
> Is it?
>
> I wwnt grepping through ruby 1.9 CVS (ok its a month or two old version)
> looking for some code that will break.
>
> I don't believe _anything_ will (currently) break.
But you should accept that others believe different.
robert
However, I must say that any time I've gotten a NoMethodError on nil, it's
been an actual bug in my algorithm that I had to fix. Your proposal probably
would have made things significantly harder for me.
Perhaps my code isn't real-world enough, or I just write code differently than
you, but I doubt this would save me much time, and would probably cost some
in actuality. When I know that a method may be legitimately called with nil,
I can usually anticipate it and code around it, so these exceptions actually
signal real bugs in most of my code.
-- Dan Doel
On Friday May 6 2005 12:44 am, John Carter wrote:
> Is it? Prove me wrong empirically...
> If I prove wrong, I will gladly retract my RCR and apologise.
The burden of proof (that this is needed) must sit on you, not on us
(that this is not needed).
Either way, I still agree with Eric, there is no reason for this to
be an RCR since the whole thing is 5 simple lines of ruby that any
user can selectively use as they see fit. If someone wants to use it,
they require a very small file. If they don't want to use it, they
don't do anything special.
--
ryand...@zenspider.com - Seattle.rb - http://www.zenspider.com/
seattle.rb
http://blog.zenspider.com/ - http://rubyforge.org/projects/ruby2c
If at some point there is some code that depends on x
being uppercase then the program will fail in the
wrong place, making debugging harder.
Even worse if x is used to generate some content, and
the format for that content mandates that it should be
all uppercase then you'll just get bad data with very
little indication of where the problem is.
--
Mark Sparshatt
___________________________________________________________
How much free photo storage do you get? Store your holiday
snaps for FREE with Yahoo! Photos http://uk.photos.yahoo.com
Yes, and the nil.blackhole switch is a very handy idea; one could turn
this on and off for blocks of code where the alternative behavior seemed
useful.
But the general idea of nil silently consuming all messages turns duck
typing into duck hunting.
James
On Sat, 7 May 2005, Ryan Davis wrote:
>
> On May 5, 2005, at 8:39 PM, John Carter wrote:
>
>> If I prove wrong, I will gladly retract my RCR and apologise.
>
> The burden of proof (that this is needed) must sit on you, not on us (that
> this is not needed).
>
> Either way, I still agree with Eric, there is no reason for this to be an RCR
> since the whole thing is 5 simple lines of ruby that any user can selectively
> use as they see fit. If someone wants to use it, they require a very small
> file. If they don't want to use it, they don't do anything special.
I'm a little puzzled by this (the idea that changes that can be
implemented in Ruby should not be RCRs), which I hadn't heard before
Eric's post, but which seems to be taking Seattle by storm :-)
I don't think implementability-in-Ruby correlates with RCR
appropriateness at all. There are lots of accepted RCRs that can be
implemented in Ruby, and since the RCR process flows into Matz's work
on the language -- and much of what Matz does can be implemented in
Ruby -- it seems like an artificial barrier.
Also, there are serious pitfalls to falling back on the solution of
just changing core behavior one program or library at a time. We've
heard from several people, for example, who would not be happy if nil
started eating messages, so presumably if they used a library that
made that change to nil, they wouldn't like it.
This situation may change if there are selector namespaces or
something along those lines in Ruby 2.0, but for the moment I would
say that the RCR process is for all proposed changes to Ruby,
including those that can be implemented in Ruby.
David
--
David A. Black
dbl...@wobblini.net
On Sat, 7 May 2005, James Britt wrote:
> Ryan Davis wrote:
>>
>> On May 5, 2005, at 8:39 PM, John Carter wrote:
>>
>>> If I prove wrong, I will gladly retract my RCR and apologise.
>>
>>
>> The burden of proof (that this is needed) must sit on you, not on us (that
>> this is not needed).
>>
>> Either way, I still agree with Eric, there is no reason for this to be an
>> RCR since the whole thing is 5 simple lines of ruby that any user can
>> selectively use as they see fit. If someone wants to use it, they require
>> a very small file. If they don't want to use it, they don't do anything
>> special.
>
> Yes, and the nil.blackhole switch is a very handy idea; one could turn this
> on and off for blocks of code where the alternative behavior seemed useful.
I don't think it would be thread-safe, would it? (I'm thinking back
to the wall I hit when working on Ruby Behaviors....)
>>
>> Yes, and the nil.blackhole switch is a very handy idea; one could turn
>> this on and off for blocks of code where the alternative behavior
>> seemed useful.
>
>
> I don't think it would be thread-safe, would it? (I'm thinking back
> to the wall I hit when working on Ruby Behaviors....)
Good point.
James
In message "Re: RCRs that can be implemented in Ruby (was: Re: Prove me Wrong! Re: RCR 303: nil should accept missing methods)"
on Sat, 7 May 2005 21:46:33 +0900, "David A. Black" <dbl...@wobblini.net> writes:
|> Either way, I still agree with Eric, there is no reason for this to be an RCR
|> since the whole thing is 5 simple lines of ruby that any user can selectively
|> use as they see fit. If someone wants to use it, they require a very small
|> file. If they don't want to use it, they don't do anything special.
|
|I'm a little puzzled by this (the idea that changes that can be
|implemented in Ruby should not be RCRs), which I hadn't heard before
|Eric's post, but which seems to be taking Seattle by storm :-)
There's no such official rule for RCRs; actually there's no official
rule for RCRs at all. But if the idea can be easily implemented in
pure Ruby, one can release it to the public before submitting an RCR
to prove its usefulness by real experiences. Besides that, if
everyone submit every idea popped in his mind, whole RCR process would
overflow. Eric (and Ryan) might think of such case.
matz.
On Sat, 7 May 2005, Yukihiro Matsumoto wrote:
> Hi,
>
> In message "Re: RCRs that can be implemented in Ruby (was: Re: Prove me Wrong! Re: RCR 303: nil should accept missing methods)"
> on Sat, 7 May 2005 21:46:33 +0900, "David A. Black" <dbl...@wobblini.net> writes:
>
> |> Either way, I still agree with Eric, there is no reason for this to be an RCR
> |> since the whole thing is 5 simple lines of ruby that any user can selectively
> |> use as they see fit. If someone wants to use it, they require a very small
> |> file. If they don't want to use it, they don't do anything special.
> |
> |I'm a little puzzled by this (the idea that changes that can be
> |implemented in Ruby should not be RCRs), which I hadn't heard before
> |Eric's post, but which seems to be taking Seattle by storm :-)
>
> There's no such official rule for RCRs; actually there's no official
> rule for RCRs at all. But if the idea can be easily implemented in
> pure Ruby, one can release it to the public before submitting an RCR
> to prove its usefulness by real experiences.
Yes, although there are cases (core changes, mostly) where people
might be reluctant to use it in production code.
> Besides that, if
> everyone submit every idea popped in his mind, whole RCR process would
> overflow. Eric (and Ryan) might think of such case.
Oh, believe me, I'm not in favor of that :-) That's why I like
RCRchive: it discourages casual RCRs, and the "I've used Ruby for five
minutes and here's what should be changed" type, by insisting on full
explanation and rationale and, where possible, implementation. (At
least it *tries* to discourage them.... :-)
I really like this. I think it is worthy of being put into a library
(like maybe as part of Facets.) For now I'll just add it to my code library.
Thanks,
Ryan
I agree. In fact, to quote
http://www.adamsmith.org/logicalfallacies/000656.php
"Shifting the burden of proof is a specialized form of the argumentum ad
ignorantiam. It consists of putting forward an assertion without
justification, on the basis that the audience must disprove it if it is
to be rejected. Normally we take it that the new position must have
supporting evidence or reason adduced in its favour by the person who
introduces it. When we are required instead to produce arguments against
it, he commits the fallacy of shifting the burden of proof."
I feel this discussion has been useful, and the NullObject pattern is
interesting, but I'm in the camp that this will do more harm than good.
To shift the burden of proof to us only tends to deflate your own
argument through logical fallacy.
Most useful programs interact with other outside programs, or of course
with a user. Using this pattern would cause silent errors that would
frustrate users and possibly crash other applications (as in Austin
Ziegler's PDF::Writer example.) If a user of some Rails application asks
to see some important bit of information, and gets nothing instead, due
to nil eating the "show_me_the_important_stuff" method, the user will
not be happy. And the developer will have to spend time figuring out why
the information was blank (which could be for any number of reasons
besides the nil-monster.)
Ryan
So your argument is that because this particular error appeared when
using the -w switch, it is just fine that the NullObject pattern
completely hid it?
Sorry, I don't buy it. In fact, this has shades of a Straw Man to me.
How about this:
class NilClass
def method_missing(*ignore) nil end
end
$counters = []
class Counter
def initialize(name)
@name = name
@count = 1
end
attr_reader :count, :name
def increase
@count += 1
end
def ==(other)
@name = other.name
end
end
def counter_factory(name)
c = Counter.new(name)
if not $counters.include? c
$counters << c
c
end
end
class DoSomething
def initialize
@name = 'DS'
@counter = counter_factory(@name)
end
def count_done
@counter.count
end
def do_it
@counter.increase
if @counter.count > 5
@counter = counter_factory(@name)
end
end
end
ds = DoSomething.new
10.times do
ds.do_it
end
puts "Have done it #{ds.count_done} times."
__END__
Contrived? Maybe. But it doesn't have warnings and it doesn't work like
it should, all because of a small (and I think common) Ruby error that
is hidden by the NullObject pattern.
Ryan
On 5/5/05, John Carter <john....@tait.co.nz> wrote:
>
> On Fri, 6 May 2005, Alexey Verkhovsky wrote:
>
> > John Carter wrote:
> >
> >> A very simple and generic way of improving the reliability of Ruby
> >> programs is to implement the NullObject pattern by allowing nil to
> >> accept all and every method instead of throwing a NoMethodError.
> >
> > I, for one, would rather see it throwing an error as it is now. Dead
> programs
> > don't tell lies.
>
> I would suggest next 5 times you have a nil class throws
> NoMethodError crash, just add this at the head of your program...
>
> class NilClass
> def method_missing( sym, *args)
> nil
> end
> end
>
> And see what happens.
>
> If, your program then works correctly, then I am right.
>
> If, your still program thows an exception or reports an error, but perhaps
> a slightly different point, then I am still right, namely this change
> doesn't hide bugs.
>
> If the program silent proceeds to do the wrong thing, then I am wrong.
>
> I ask members of this list to actually try this experiment the next couple
> of times they hit a nil throws NoMethodError and send the results to me.
>
> I will summarize to the list.
>
> If I prove wrong, I will gladly retract my RCR and apologise.
>
> John Carter Phone : (64)(3) 358 6639
> Tait Electronics Fax : (64)(3) 359 4632
> PO Box 1645 Christchurch Email : john....@tait.co.nz
> New Zealand
>
> This rock is covered by a very very thin layer of life. (Think 6000km
> of rock followed by a meter or so of biomass.)
>
>
--
Bill Atkins
Interesting quote, however for an alternative point of view consider
the scientific method, where people postulate hypothesis which can
never be proved true (only in general agreement with observed data)
but one single contradictory fact can invalidate the entire
hypothesis. I think this is more in alignment with John's baiting,
i.e. he has postulated this is not a problem in real world
circumstances. He has tried to come up with the code which counters
this himself and has not found it, so he is requesting the same of a
broader audience.
My $0.02 :)
Regards,
Jason
http://blog.casey-sweat.us/
> You may, however, be left with incorrect output.
>
> "\n#{@oid} 0 obj\n<</Type /Page /Parent #{@owner.oid} 0 R >>"
>
> If @owner is nil, then using your proposal I will get:
>
> 234 0 obj
> <</Type /Page /Parent 0 R >>
Hmm. Interesting.
Hard real, live, data.
I like it.
Let's look at it a bit more closely.
How did the nil get into @owner? Would it have been picked up by -w?
Was it placed there yourself in the meaning "uninitialised" or in the
meaning "no thing here"? By what route did it arrive?
Given my new proposal of having an uninitialised vs nothing
types of nil?
Could we design things in a way that would resolve your
issue?
John Carter Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : john....@tait.co.nz
New Zealand
It originates from just one of the 6 billion yet vastly outnumbered
humans.
I trust you will keep this perspective and context in mind when
reacting to this email.
Well, one could redesign so that nil is never returned from
any method at all for any purpose. While a valid suggestion
as such, it is sort of moot as far as the merits or your
original proposal go.
>John Carter
E
--
template<typename duck>
void quack(duck& d) { d.quack(); }
> How did the nil get into @owner? Would it have been picked up by -w?
> Was it placed there yourself in the meaning "uninitialised" or in the
> meaning "no thing here"? By what route did it arrive?
In this *particular* case, it is usually a case of forgotten
initialization -- but -w only helps so much. But my point was more
illustrative than anything else. This could have happened with another
line of code than I picked, perhaps from malformed user input that was
improperly guarded against. Without an exception on an attempt to call
a method on nil, it would be difficult to trace this.
> Given my new proposal of having an uninitialised vs nothing
> types of nil?
I think that the discussion in relation to relational databases is an
informative one here. Originally, Codd specified multiple types of
NULL -- for much the same reason you have. The SQL standard combined
these into a single NULL. In later life, though, Codd and his
successors have determined that NULL values in database tables are bad
and represent a bad logical table design.
We already have a problem where sometimes we need #nil_or_empty? I
don't want to add a case of #uninitialised_or_nil_or_empty?
obj.meth1().meth2().meth3()
which should not break if meth2 for some cause returns nil.
On the other hand many people claim this will hide errors (I agree here).
It seems there are two kinds of nils: expected and unexpected ones.
So why dont we deal with the expected ones seperately:
==========================================================
class Object
def nil_friendly
self
end
end
class NilClass
def nil_friendly
Blackhole.instance
end
end
class Blackhole
include Singleton
def method_missing( sym, *args)
nil
end
end
## Now this works:
obj.meth1().meth2().nil_friendly.meth3()
==========================================================
So by inserting .nil_friendly (choose a better/shorter name for this) you
_explicitly_ tell that you don't care if nil ist returned.
This will not break any existing code, will not hide errors, but gives
shorter code without explicit ifs.
Comments?
Klaus Stein
--
http://lapiz.istik.de/
The Answer is 42. And I am the Answer. Now I am looking for the Question.
What about #nil?
robert
I'm not sure I'm following you here. If it's an expected nil (like for
example an explicitely initialized instance variable) shouldn't this then
behave similarly to nil with regard to this test? I imagine there will be
two equally sized camps in favour for each of the two options...
Kind regards
robert
I don't see why anyone should try something like obj.nil_friedly.nil?,
because I know that this will return false :-)
But I am interested if there are other real drawbacks?
Klaus