August 26, 2004
On Thu, 26 Aug 2004 11:34:15 +1000, Matthew <admin.hat@stlsoft.dot.org> wrote:
> "Walter" <newshound@digitalmars.com> wrote in message news:cgirt4$2fvp$1@digitaldaemon.com...
>>
>> "Arcane Jill" <Arcane_member@pathlink.com> wrote in message
>> news:cgi05f$234t$1@digitaldaemon.com...
>> > In article <cght30$21u3$1@digitaldaemon.com>, Matthew says...
>> >
>> > >unquantifiable and unpredictable throwing of exceptions at any time 
>> after
>> the
>> > >deployment of my code.
>>
>> They are not any more unpredictable than any other bugs in your program -
>> and at least you have a chance of finding this bug before release. The
>> superfluous return has proveably *less* chance of being found before
>> release.
>>
>> > It's /much/ worse than that if you compile with the "-release" flag. 
>> These
>> are
>> > asserts, not exceptions. They vanish in a release build, leaving you 
>> with
>> > /seriously/ undefined behavior.
>>
>> Yet executing a superfluous return that returns a value that was never
>> intended to be returned is an easier to find bug? I don't see how. I'd
>> *much* rather have the assert.
>>
>> The principle here is that, as much as practical, program bugs should result
>> in the program stopping immediately upon detection and issuing some
>> appropriate error message. Trying to soldier on with some arbitrary return
>> value will just cause your program to fail somewhere else in a far more
>> obscure manner.
>>
>> This discussion reminds me of an old joke about assembler programming:
>>
>>     ... various assembler instructions ...
>>     HALT        ; stop program
>>     HALT        ; if skidding
>>     HALT        ; needed if program was running really, really fast
>
> I completely agree that having the program fail if its in an invalid state is preferable to soldiering on. Absolutely
> completely agree with that.
>
> But I also prefer *in every conceivable circumstance* to have the compile refuse to compile than insert a runtime check.
> To me these things are completely different, and one should not be mixed with the other. Since C++ is able to, in almost
> all cases, find it at compile time, then I fail to see why D shouldn't. I accept that neither C++ nor D can find every
> one, in which case I prefer the assert to arbitrary behaviour. But "we can't find 100% at compile time" is no
> justification for "we won't look for *any* at compile time".

I agree with Matthew here.

I an ideal world all sources of bugs would be caught at the compile step.

Failing that, they should be caught at runtime, causing an exception which reports to the user the location of the fault. In a debug build this could be the file and line number, in release 'Dave's suggestion might be workable (I don't know enough to comment on it).

It seems to me that we all agree on the principle but not the implementation, are the compile time checks worth the effort involved in adding them? Matthew says "yes", I agree.. what do you think Walter?

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 26, 2004
"Matthew" <admin.hat@stlsoft.dot.org> wrote in message news:cgjf0g$2o40$1@digitaldaemon.com...
> I completely agree that having the program fail if its in an invalid state
is preferable to soldiering on. Absolutely
> completely agree with that.
>
> But I also prefer *in every conceivable circumstance* to have the compile
refuse to compile than insert a runtime check.
> To me these things are completely different, and one should not be mixed
with the other. Since C++ is able to, in almost
> all cases, find it at compile time, then I fail to see why D shouldn't. I
accept that neither C++ nor D can find every
> one, in which case I prefer the assert to arbitrary behaviour. But "we
can't find 100% at compile time" is no
> justification for "we won't look for *any* at compile time".

But the compiler requiring a superfluous return statement is not finding a bug nor is it helping find a bug. It is, often enough, hiding a bug. I've often had to insert such superfluous returns to satisfy various C++ compilers.


August 26, 2004
"Walter" <newshound@digitalmars.com> wrote in message news:cgk28d$3i$1@digitaldaemon.com...
>
> "Matthew" <admin.hat@stlsoft.dot.org> wrote in message news:cgjf0g$2o40$1@digitaldaemon.com...
> > I completely agree that having the program fail if its in an invalid state
> is preferable to soldiering on. Absolutely
> > completely agree with that.
> >
> > But I also prefer *in every conceivable circumstance* to have the compile
> refuse to compile than insert a runtime check.
> > To me these things are completely different, and one should not be mixed
> with the other. Since C++ is able to, in almost
> > all cases, find it at compile time, then I fail to see why D shouldn't. I
> accept that neither C++ nor D can find every
> > one, in which case I prefer the assert to arbitrary behaviour. But "we
> can't find 100% at compile time" is no
> > justification for "we won't look for *any* at compile time".
>
> But the compiler requiring a superfluous return statement is not finding a bug nor is it helping find a bug. It is, often enough, hiding a bug. I've often had to insert such superfluous returns to satisfy various C++ compilers.

I've never had to insert one. I've always been able to sensibly reorder the code such that the return was both natural and valid.

In such cases, why not have a "noreturn" keyword which would both serve to suppress the compiler's eagerness, and be an *explicit* documentation of the assertion/exception throw point that such a keyword would cause?

AFAICS, that's the best of all worlds, and everyone's happy. No?



August 26, 2004
In article <cgiq4b$2f6o$1@digitaldaemon.com>, Walter says...

>I disagree strongly. When I am maintaining/reviewing code, every statement must be justified. If I see a superfluous "return 0;", I'll look at all the callers to make sure they can handle a 0 value. If they can't, it isn't clear at all that they don't need to. I like to be able to look at code and know that "this cannot happen".
>
>And if the superfluous return *does* get executed because of a different bug, now you've got a garbage return value that's seeped into your data,

I could always write:

#    throw new Exception(); // this statement is never reached.

instead of:

#    return 0; // this statement is never reached.

Jill


August 26, 2004
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message news:cgk4g7$24i$1@digitaldaemon.com...
> I could always write:
>
> #    throw new Exception(); // this statement is never reached.
>
> instead of:
>
> #    return 0; // this statement is never reached.


Yes, you could always write a comment. The trouble with comments, though, is they are always wrong, out of date, or missing. When examining code, I prefer to rely on the semantics of the language <g>.


August 26, 2004
"Derek Parnell" <derek@psych.ward> wrote in message news:cgjb3l$2mdv$1@digitaldaemon.com...
> <anecodote>
> Recently, in some code of mine, I came across an complex 'if/else if'
> statement, in which I realized the final 'else' condition would never be
> met. I'd left it for ages without an 'else' clause, but last week, just
for
> a sense of completeness, I coded something like ...
>
>    else
>        Abort("LOGIC ERROR #1: You should never see this but the Handle is
> not owned by owner");
>
> I released the code and almost immediately I had users saying that they were getting this weird error message. It turned out that there were at least three different conditions that fell through to the abort code. They were all bugs in code quite distant from this 'else', but until I added this superfluous 'else' code, I never knew about the bugs. (They caused a slow resource leak).
>
> So I fixed the bugs but still I've left in the abort code, just in case I've messed up elsewhere.
>
> </anecodote>

That's just the kind of problem the check at the implicit return is supposed to detect.


August 26, 2004
In article <cgk46j$209$3@digitaldaemon.com>, Matthew says...

>In such cases, why not have a "noreturn" keyword which would both serve to suppress the compiler's eagerness, and be an *explicit* documentation of the assertion/exception throw point that such a keyword would cause?
>
>AFAICS, that's the best of all worlds, and everyone's happy. No?

Matthew's idea is better than mine. I support it. Let's do this. If executed, "noreturn" would be almost exactly equivalent to "throw new Error()", indicating a software error - i.e. bug.

Arcane Jill



August 26, 2004
"Matthew" <admin@stlsoft.dot.dot.dot.dot.org> wrote in message news:cgk46j$209$3@digitaldaemon.com...
>
> "Walter" <newshound@digitalmars.com> wrote in message
news:cgk28d$3i$1@digitaldaemon.com...
> > But the compiler requiring a superfluous return statement is not finding
a
> > bug nor is it helping find a bug. It is, often enough, hiding a bug.
I've
> > often had to insert such superfluous returns to satisfy various C++ compilers.
>
> I've never had to insert one. I've always been able to sensibly reorder
the code such that the return was both natural
> and valid.

I've had to insert them for things like:

int func()
{
    while (1)
    {    ...
        if (condition) return value;
        ...
    }
}

> In such cases, why not have a "noreturn" keyword which would both serve to
suppress the compiler's eagerness, and be an
> *explicit* documentation of the assertion/exception throw point that such
a keyword would cause?
>
> AFAICS, that's the best of all worlds, and everyone's happy. No?

I don't understand why a thrown exception with an appropriate message is such an anathema. They're good things, they tell you in no uncertain terms that there's a bug in the program, and where that bug is. The noreturn keyword would be redundant - a closing } without a return exp; for a value returning function implicitly specifies that it's an error to fall off the end. All the language does is make such errors impossible to overlook. If the assert message is "NoReturnException file foo.d line 1234", isn't that plenty?


August 26, 2004
"Walter" <newshound@digitalmars.com> wrote in message news:cgkaql$4gq$1@digitaldaemon.com...
>
> "Matthew" <admin@stlsoft.dot.dot.dot.dot.org> wrote in message news:cgk46j$209$3@digitaldaemon.com...
> >
> > "Walter" <newshound@digitalmars.com> wrote in message
> news:cgk28d$3i$1@digitaldaemon.com...
> > > But the compiler requiring a superfluous return statement is not finding
> a
> > > bug nor is it helping find a bug. It is, often enough, hiding a bug.
> I've
> > > often had to insert such superfluous returns to satisfy various C++ compilers.
> >
> > I've never had to insert one. I've always been able to sensibly reorder
> the code such that the return was both natural
> > and valid.
>
> I've had to insert them for things like:
>
> int func()
> {
>     while (1)
>     {    ...
>         if (condition) return value;
>         ...
>     }
> }
>
> > In such cases, why not have a "noreturn" keyword which would both serve to
> suppress the compiler's eagerness, and be an
> > *explicit* documentation of the assertion/exception throw point that such
> a keyword would cause?
> >
> > AFAICS, that's the best of all worlds, and everyone's happy. No?
>
> I don't understand why a thrown exception with an appropriate message is such an anathema. They're good things, they tell you in no uncertain terms that there's a bug in the program, and where that bug is. The noreturn keyword would be redundant - a closing } without a return exp; for a value returning function implicitly specifies that it's an error to fall off the end. All the language does is make such errors impossible to overlook. If the assert message is "NoReturnException file foo.d line 1234", isn't that plenty?

You don't see the difference between

    - a hidden, implicit insertion of an exception throw that may or may not ever happen, and which is not (easily)
amenable to code review, and not at all instrumentable
    - an overt, instrumentable, expression on the part of the code's author that indicates his/her expressed intention
that no return is expected (by his/her design) and that he/she is asking for an overt, explicit insertion of an
exception throw that may or may not ever happen

? Really?

If so, I give up, as I cannot conceive of any better way of putting it. It seems plainer than the nose on my face to me.


August 26, 2004
In article <cgkaql$4gq$1@digitaldaemon.com>, Walter says...

>I don't understand why a thrown exception with an appropriate message is such an anathema. They're good things, they tell you in no uncertain terms that there's a bug in the program, and where that bug is.

You're completely missing the point. Your statement above is obviously true, and no-one is disagreeing with you. All you're doing is stating the obvious. But it's irrelevant, so I can only assume that you're just not /getting/ what we're complaining about.

THIS SHOULD NOT COMPILE:

#    int f(int n)
#    {
#        if (n == 1) return 1;
#    }

I want the error reported /at compile time/, not at run-time. I want the compiler to tell me "not all execution paths return a value" /at compile time/. And if the way to make the compile-error go away is to change the code to:

#    int f(int n)
#    {
#        if (n == 1) return 1;
#        noreturn;
#    }

Then what is wrong with that? Furthermore, it should be a compile-time error to place any code after "return", "noreturn", "throw", "goto" or "break", unless there's a label or a right-brace. The error message should be "Unreachable code at file xxxx line xxxx".


>The noreturn
>keyword would be redundant - a closing } without a return exp; for a value
>returning function implicitly specifies that it's an error to fall off the
>end. All the language does is make such errors impossible to overlook. If
>the assert message is "NoReturnException file foo.d line 1234", isn't that
>plenty?

The error message is not a problem (although it should be present in release builds, not just debug builds). The problem is that DMD compiles code which should not compile.

Arcane Jill