Re: A C++ Whishlist

From: Ram Firestone (bichir_at_covad.net)
Date: 03/20/04


Date: 19 Mar 2004 19:45:50 -0800

Kevin Goodsell <usenet2.spamfree.fusion@neverbox.com> wrote in message news:<%lH6c.48063$aT1.25034@newsread1.news.pas.earthlink.net>...
> Ram Firestone wrote:
> > Kevin Goodsell <usenet2.spamfree.fusion@neverbox.com> wrote in message news:<CTr6c.28277$%06.19752@newsread2.news.pas.earthlink.net>...
> >
> >>Ram Firestone wrote:
> >>
> >>>Kevin Goodsell <usenet2.spamfree.fusion@neverbox.com> wrote in message news:<YWj6c.27591$%06.991@newsread2.news.pas.earthlink.net>...
> >>>
> >>>
> >>>>Ram Firestone wrote:
> >>>>
> >>>>
> >>>>>As I said elsewhere. What are you going to do when you catch all these
> >>>>>null pointers.
> >>>>
> >>>>Uh... signal an error, maybe?
> >>>>
> >>>
> >>>
> >>>Which typically happens for free anyway.
> >>>
> >>
> >>Show me where it says that in the standard.
> >>
> >
> >
> > It's not in any standard. It just does.
>
> No, it doesn't. I'm reasonably confident that it doesn't happen on the
> vast majority of computers in the world.
>

In the vast majority of member functions the first thing you will do
is access a member which will crash the program. (For the fourth time)
If I feel it needs an extra check because it won't crash cleanly I may
put it in. But I do it on a case by case basis.

> >>
> >>I don't even need to look. I've programmed systems like that. You'd be
> >>surprised (apparently) how many architectures have address 0 as a
> >>perfectly valid memory address, and also use it to represent a null
> >>pointer (because it's easy, and there may not be a more appropriate
> >>address anyway). All the world is not a desktop system.
> >>
> >
> >
> > Ok name some. Yeah I would be surprised how many. Let's see not Lunix,
> > Windows, IBM workstation, mainframe, HP/UX ..... I'm really curious.
>
> Like I said, all the world's not a desktop system. In fact, most of the
> computers in the world aren't. The 8051 is the only processor I'm
> familiar enough with to say for sure that it uses 0 as a valid memory
> location, and (with certain tool-chains, such as Keil C51) as the null
> pointer value. But I'm sure that if you looked you'd find that most
> micro-controllers operate this way. And they are *much* more prevalent
> than the systems you named.
>

All your telling me is that if your are coding for a microcontroler
(typically a specific task) you put in extra checks. BTW I see you
picked a compiler that isn't quite ANSI complient and on top of that I
don't think void * NULL is zero. Kind of puts a hole in your standares
argument doesn't it.

> > And please don't say PDP-8 because it's not exactly modern. In any
> > case once you find one you will then have to find a compiler on that
> > system that doesn't pass NULL to members in order for your argument to
> > have any relevance to this thread.
>
> Not at all. I'm not, nor have I been, talking about your lame idea of
> allowing member function calls from null pointers.

Which is what the thread is about BTW.

> I have been talking
> about this, in which you indicate that you are OK with writing broken code:
>
> >>void func(foo *p)
> >>> > > {
> >>> > > std::cout << p->a << std::endl;
> >>> > > }
> >>> > >
> >>> > > int main()
> >>> > > {
> >>> > > foo *f = NULL;
> >>> > > func(f);
> >>> > > }
> >>> > >
> >>> > > Is function "func" wrong?
>

Well if you bothered to read the rest of the discussion you would know
that this code was part of a discussion on passing NULL pointers. i.e.
I KNOW IT IS BROKEN. The question is if it is broken in func or in
main. I say main others say func. But there is no question it's
broken.

> >> >
> >> > Yes, 'func' is incorrectly written. 'func' should ensure that 'p->a'
> >> > is never invoked with p == 0 or, at the very least, document that
> >> > calling it with a 0 argument results in undefined behavior (which
> >> > means that anything at all could happen).
> >> >
>
> > Ok well obviously we have a fundamental coding style difference,
> > which we are not going to settle here. I could easily say your code
> > is incorrectly written because it wastes CPU time. But what's the
> > point these or personal choices.
>
>
> >
> >
> > If you want to check every parameter at the cost of speed, be my
> > guest. I'm not even going to say it's wrong. What I am going to say is
> > unless you also check the this pointer you aren't checking every
> > parameter and you can still get a crash which is the whole point.
>
> This is an absolutely stupid argument. Code is not required or expected
> to be correct in the face of external errors, nor can it be. My code is
> broken if you violate the rules of the language before calling it? Yeah,
> well, all the code in the universe is broken if I toss the computer into
> molten lava before using it. I guess all those coders forgot to add the
> "processor melted" check to their code.
>

WHAT!?!?! YOU are the one advocating putting in checks for external
errors. Passing NULL is and external error. The same as passing a
billion other bad addresses which you don't and can't check for. I'm
simply pointing out you can't check for everything.

> *Your* code, however, is incorrect due to its own error, not an external
> error.

NO it's an external error. You can't call func with 0! That's
external. This is the same as most C library functions. Also even if I
checked for 0 I couldn't check for the rest of the bad addresses. How
in gods name is that internal?

>
> >>>
> >>>Except your program will fail at the same rate as mine.
> >>
> >>I doubt that.
> >
> >
> > Just because you check for unrecoverable errors doesn't make them
> > happen less. All it means is you may print a better message. But wait
> > you aren't checking the this pointer.
>
> See, you missed the point. I was insinuating that you are a lousy coder,
> and your programs fail frequently.

No you have missed the point of this whole thread.

>
> And the 'this' pointer is still completely irrelevant.
>

That's what this thread is about "A C++ Whishlist". Allowing calls
non-virtual member calls through NULL is my wish. You may still not
like it, but it's what I'm advocating.

> >
> > Sorry but in my experience the user doesn't care about the line or
> > file. If he even writes it down you are lucky.
>
> True, but 1) they at least have the option of trying to help solve the
> problem, and 2) my program has the option of doing something more useful
> with the error message, such as emailing it back to me.
>
> > The frequency of
> > crashes is what's going to loose you customers. In my case lack of
> > speed will also loose me customers. In any case if he does have a core
> > I will be able to find out much more about the crash then you will.
>
> You are still using a very narrow frame of reference. Core files are
> generated in the vast minority of cases.

I program for my users frame of reference.

>
> Besides that, you're still ignoring the point that my program has a
> chance of recovering, while yours does not.

That all depends on what you are catching and what you will do with
it. That's not a blanket statement. Also I said I TRY TO HANDLE
RECOVERABLE ERRORS.

>
> >
> > Checking every member of every parameter for correctness would waste
> > huge amounts of time.
>
> Did you time it?

If you encapsulate your data you often end up writing many single line
inline functions. With a check you can double, triple or more the size
and runtime of code in these functions and it's even worse because you
are adding an if statement which is time consuming.

>
> > Why would you stop at just checking for NULL
> > pointers? On many architectures you loose the pipelineing when you do
> > an if.
> >
> >
> >>But I'd say 98% of the time it's worth it to have the extra checks. I
> >>might, for example, set up my program to do whatever it can to save the
> >>user's data in the event of an error - even an unrecoverable logic
> >>error. Or the exception could abort the current operation (and provide
> >>some details about what happened) without killing the whole program. In
> >>general, optimizing by removing safeguards is a bad policy, and won't
> >>improve performance much.
> >
> >
> > Hey go wild. That isn't the point of this thread. My claim is that
> > allowing call though NULL isn't going to change much in the real
> > world.
>
> Oh, well, in that case you're just wrong. Nearly every member function
> ever written in code that is intended to be standards-compliant and
> robust would need to be modified. And every programmer who writes code
> with those concerns in mind has to write their code differently.
>

The standard does not say "the this pointer cannot be NULL". It is
currently undefined. It might be NULL currently. With my change it can
be NULL. It's not a big difference considering on almost all compilers
it will be NULL if you call it with NULL. Again why is NULL any worse
than any other bad address? Your so called robustness is vaporware.
Your classes were never robust before. You said yourself you can crash
code with bad input. NULL is just one possible bad input.

You are arguing both sides. First you claim you want to check for
quality of input and now you are complaining about checking for
quality of input. I'm never going to buy your standards argument. Text
written on a piece of paper someplace doesn't change how your code
runs. For most if not all compilers my change would be a noop. The
standards committee is already done much worse than this. They are
changed things that will eventually break compiles. On HP/UX several
things have already broken.

> > In fact with your mentality you would feel you then have to
> > check the this pointer which would give you the kind of error checking
> > you say you like. As it stands now you are working under the misguided
> > perception that the this pointer will never be NULL.
>
> That is not a misguided perception. That is a guarantee provided by the
> C++ standard. Of course, you have to add the requirement that undefined
> behavior has not previously been invoked, but you need that requirement
> for any code to make any sense at all.
>
> My assumption that 'this' is not NULL is every bit as valid as your
> assumption that the processor hasn't been melted by molten lava.
>
> >
> >
> >>I've used too many programs written by people like you. You can write
> >>brittle programs that crash without reasonable diagnostics or recovery
> >>attempts if you want to. I'll make my programs robust. And avoid yours.
> >>
> >
> >
> > In reality test suits make far more difference in program reliability
> > than anything we have talked about here. So if you want to make your
> > programs robust better have large automated test suits. By the way the
> > Mars rover's computer did crash. I'm sure they were so so careful when
> > they wrote the software. The problem was it wasn't tested enough. I
> > just thank god they were able to fix it.
> >
> > Also I'll avoid your programs too as I'm sure they run at a snails
> > pace. On the other hand maybe they don't do enough to have that
> > problem.
> >
> >
> >>By the way, you've yet to answer the point that started this discussion:
> >>You were defending a practice of dereferencing pointers without checking
> >>for NULL, and *without documenting that the function should not be
> >>called with a null pointer*. In other words, your function is broken by
> >>definition (it violates its specification), and you seem to be OK with that.
> >>
> >>-Kevin
> >
> >
> > What started this discussion is my advocating member call through
> > NULL. As for documentation, I would document the function to the
> > extent that any non-idiot programmer could use it properly.
>
> Then why didn't you say so in the first place? Instead, you indicated
> that dereferencing a pointer without documenting that a null pointer
> should not be used represented a "fundamental coding style difference".
> If you had just said "Oh, well, I would document it of course," then we
> could have avoided all (well, most of) this.

Because I don't have to say a NULL pointer should not be used just
like I don't have to say a bad address should not be used, and I don't
have to say your left pinky should not be used. All I have to say is
the parameter is a pointer to an object of type foo. NULL is not a
pointer to foo.

K&R :

String Functions: <string.h>

".....In the following table, variables s and t are of type char *. cs
and ct are of type const char *; n is of type size_t; and c is an int
converted to char."

Notice it doesn't say anything about NULL. Why? Because it's obvious
to everyone except apparently you.

>
> There's nothing inherently wrong with *not* checking parameters, as long
> as your assumptions are documented. But in my opinion the added safety
> is well worth it most of the time, because the only thing it costs you
> is a little tiny bit of execution time. And if the program is determined
> to be stable enough that the tests are no longer required, you can
> remove them (through a build option - I wouldn't remove them
> altogether). In some cases these tests can have a very significant
> affect on the quality and usefulness of the program.
>
> As an example, the audio editing application Cool Edit doesn't crash
> very often, but when it does crash it does an amazing job of saving the
> state of your work and restoring it later. This is very significant
> because it deals with so much data, and operations on those data are so
> time consuming and not always easy to reproduce. A crash that loses your
> work could be a major problem. Fortunately, this usually doesn't happen
> (based on my limited experience with it crashing - I've only seen it
> happen a few times). This level of robustness is what all serious
> programs should strive for.
>
> -Kevin

Well there we go. Your idea of robustness is a (Mac? PC?) program that
crashes sometimes. I'm sure I have much worse problems to solve then
your audio editing software. We deal with layout files that can be
over 20 Gig each. I can't even read it into memory. I had to write my
own virtual memory manager, do partitioning, paging etc. And that's
before I even get to the processing algorithms. So have fun RUNNING
Cool Edit. I find the guys who nit-pick about paper standards
typically don't have to deal with any hard problems. The standard is
just a baseline. If you want to protect your code from crashing then
do so. If you want to make it fast then do so. But don't tell me I
don't have to check for NULL because the standard says this something
is undefined. You may very well want to check for it anyway if you
want your code to be more robust, or you may want to leave the check
out if there is a speed consideration. Go pray to your document now.

Ram



Relevant Pages

  • Re: A C++ Whishlist
    ... >>Show me where it says that in the standard. ... >>pointer (because it's easy, and there may not be a more appropriate ... allowing member function calls from null pointers. ... > I will be able to find out much more about the crash then you will. ...
    (comp.lang.cpp)
  • Re: Youre appointed as Portability Advisor
    ... None of its behaviour is undefined by the Standard. ... to write to member A of a union and then read from member B, ... character type that treats the thing as an array of bytes. ... dereferencing a pointer to one ...
    (comp.lang.c)
  • Re: A C++ Whishlist
    ... > Ram Firestone wrote: ... It's not in any standard. ... >> NULL pointer reference. ... it doesn't mean the program has to crash). ...
    (comp.lang.cpp)
  • Re: dereferencing memory location some time after deleting the same one
    ... The Standard says that any program that attempts to dereference ... > a pointer after the pointer has been deleted, ... memory from the kernel VM and manages the allocation of little pieces ... > He could get a crash. ...
    (comp.lang.cpp)
  • Re: Leading padding in unions
    ... Somewhere there is a provision that a pointer to the first ... address of each member. ... One of the defects of the standard is that it fails to guarantee something that almost every C programmer has relied upon frequently, which was probably intended to be guaranteed by the committee: that any conversion of a non-null pointer value from one pointer type to another that does not have undefined behavior, produces a new pointer that points at the same location in memory as the original. ...
    (comp.lang.c)