On 5/6/05, Cyent <cyent / xtra.co.nz> wrote:
> On Sat, 07 May 2005 02:28:18 +0900, Austin Ziegler wrote:
>> On 5/5/05, John Carter <john.carter / tait.co.nz> wrote:
>> 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.
> Ah, but _would_ it. On any other object I would agree with you.
> But nil occupies a special place in the ruby world.

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.

-austin
-- 
Austin Ziegler * halostatue / gmail.com
               * Alternate: austin / halostatue.ca