www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - AssertError on missing return?

reply J C Calvarese <jcc7 cox.net> writes:
I think I found a bug. I could be wrong. ;)

bit b;

int main()
{
     if (b)
         return 0;
}

Note the lack of a return statement when b is false (which is always).

It compiles fine. At runtime, an error occurs...
Error: AssertError Failure bug.d(7)

I understand it can be difficult/undesirable for the compiler to catch a 
problem like this during compile. If the lack of a return is cause of 
the AssertError, I hope it could at least be renamed to NoReturnError or 
something.

(I've observed this with DMD 0.98 and DMD 0.100 on WinXP.)

-- 
Justin (a/k/a jcc7)
http://jcc_7.tripod.com/d/
Aug 23 2004
next sibling parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"J C Calvarese" <jcc7 cox.net> wrote in message
news:cge2ru$4gs$1 digitaldaemon.com...
 I think I found a bug. I could be wrong. ;)

 bit b;

 int main()
 {
      if (b)
          return 0;
 }

 Note the lack of a return statement when b is false (which is always).

 It compiles fine. At runtime, an error occurs...
 Error: AssertError Failure bug.d(7)

This is expected behaviour, and was discussed before. Some people argued that compiler should check that every code path ends in return or throw and i think Walter said it was too complicated. The only requirement now is that function has at least one return statement, so you can trick compiler to do bad things easilly: int func() { goto skipret; return 0; skipret:; } As far as compiler is consearned this is a valid func(even though return isn't reachable), but will also get you AssertError :(
 I understand it can be difficult/undesirable for the compiler to catch a
 problem like this during compile. If the lack of a return is cause of
 the AssertError, I hope it could at least be renamed to NoReturnError or
 something.

 (I've observed this with DMD 0.98 and DMD 0.100 on WinXP.)

 --
 Justin (a/k/a jcc7)
 http://jcc_7.tripod.com/d/

Aug 23 2004
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"Ivan Senji" <ivan.senji public.srce.hr> wrote in message
news:cgemi7$e6i$1 digitaldaemon.com...
 "J C Calvarese" <jcc7 cox.net> wrote in message
 news:cge2ru$4gs$1 digitaldaemon.com...
 I think I found a bug. I could be wrong. ;)

 bit b;

 int main()
 {
      if (b)
          return 0;
 }

 Note the lack of a return statement when b is false (which is always).

 It compiles fine. At runtime, an error occurs...
 Error: AssertError Failure bug.d(7)

This is expected behaviour, and was discussed before. Some people argued that compiler should check that every code path ends in return or throw and i think Walter said it was too complicated. The only requirement now is that function has at least one return statement, so you can trick compiler to do bad things easilly: int func() { goto skipret; return 0; skipret:; } As far as compiler is consearned this is a valid func(even though return isn't reachable), but will also get you AssertError :(

If D's simpler than C++ to implement, and C++ compilers can do this pretty much in their sleep, then why should D not? IMO, it's ridiculous that code such as
 bit b;

 int main()
 {
      if (b)
          return 0;
 }


can get past the compiler. Period.
Aug 24 2004
next sibling parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Matthew" <admin stlsoft.dot.dot.dot.dot.org> wrote in message
news:cgh9ms$1ohc$1 digitaldaemon.com...
 "Ivan Senji" <ivan.senji public.srce.hr> wrote in message

 "J C Calvarese" <jcc7 cox.net> wrote in message
 news:cge2ru$4gs$1 digitaldaemon.com...
 I think I found a bug. I could be wrong. ;)

 bit b;

 int main()
 {
      if (b)
          return 0;
 }

 Note the lack of a return statement when b is false (which is always).

 It compiles fine. At runtime, an error occurs...
 Error: AssertError Failure bug.d(7)

This is expected behaviour, and was discussed before. Some people argued that compiler should check that every code path ends in return or throw and i think Walter said it was too complicated. The only requirement now is that function has at least one return statement, so you can trick compiler to do bad things easilly: int func() { goto skipret; return 0; skipret:; } As far as compiler is consearned this is a valid func(even though return isn't reachable), but will also get you AssertError :(

If D's simpler than C++ to implement, and C++ compilers can do this pretty

You are absoulutelly right. And the problem is i can't see a problem in implementing it: bool statementListEndsInReturn(StatementList sl) { if(typeid(sl.laststatement) === typeid(ReturnStatement))return true; if(typeid(sl.laststatement) === typeid(IfStatement)) return statementListEndsInReturn(sl.laststatement.truepart) && statementListEndsInReturn(sl.laststatement.elsepart); //maybe a couple of more cases return false; }
 IMO, it's ridiculous that code such as

 bit b;

 int main()
 {
      if (b)
          return 0;
 }


can get past the compiler. Period.

Aug 25 2004
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Matthew" <admin stlsoft.dot.dot.dot.dot.org> wrote in message
news:cgh9ms$1ohc$1 digitaldaemon.com...
 If D's simpler than C++ to implement, and C++ compilers can do this pretty

I've never seen a C++ compiler get it completely right, and there's no way that they can. I don't like putting in meaningless return statements in code that will never be executed and that will confuse the maintenance programmer, just to get the compiler to stop issuing an error message. But I do want to find out if that meaningless return statement ever does happen. There's no way to do it 100% without a runtime check, hence that's what the language does.
Aug 25 2004
next sibling parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <cghkuj$1uni$1 digitaldaemon.com>, Walter says...

I don't like putting in meaningless return statements in code
that will never be executed and that will confuse the maintenance
programmer, just to get the compiler to stop issuing an error message.

I'd rather have it that way round that the current way round. False positives (unnecessary returns) are better than false negatives (failing to reach a return at all) in this situation. Consider: # int f(int n) # in # { # assert(n > 3 && n < 10); # } # body # { # if (n >= 4 && n < 8) return 3; # if (n >= 8 && n < 10) return 4; # // The compiler will insist on an unnecessary return here. # } So the compiler demands a superfluous return. Big deal. I can live with that. Better a statement which won't get executed (and therefore won't affect the running of my program in any way at all) than a run-time assert in a debug build and a crash in a release build.
But I do want to find out if that meaningless return statement ever does
happen. There's no way to do it 100% without a runtime check,

Yes. No-one's arguing with that. I just don't think it that important. I'd rather have a compiler which claimed that good code is bad, than a compiler which claimed that bad code is good. I've had crashes because of this situation, and I'd rather not have any more. Arcane Jill
Aug 25 2004
parent reply "Walter" <newshound digitalmars.com> writes:
"Arcane Jill" <Arcane_member pathlink.com> wrote in message
news:cghqva$211l$1 digitaldaemon.com...
 In article <cghkuj$1uni$1 digitaldaemon.com>, Walter says...

I don't like putting in meaningless return statements in code
that will never be executed and that will confuse the maintenance
programmer, just to get the compiler to stop issuing an error message.

I'd rather have it that way round that the current way round. False

 (unnecessary returns) are better than false negatives (failing to reach a

 at all) in this situation. Consider:

 #    int f(int n)
 #    in
 #    {
 #        assert(n > 3 && n < 10);
 #    }
 #    body
 #    {
 #        if (n >= 4 && n < 8) return 3;
 #        if (n >= 8 && n < 10) return 4;
 #        // The compiler will insist on an unnecessary return here.
 #    }

 So the compiler demands a superfluous return. Big deal. I can live with

 Better a statement which won't get executed (and therefore won't affect

 running of my program in any way at all) than a run-time assert in a debug

 and a crash in a release build.

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, possibly corrupting things in unpredictable ways. I cannot see how this is superior. With the assert, you get an *unambiguous indication* of a bug in your program. I pick an unambiguous and repeatable indication of an error every time over a bad value sneaking unobserved into my data.
But I do want to find out if that meaningless return statement ever does
happen. There's no way to do it 100% without a runtime check,

Yes. No-one's arguing with that. I just don't think it that important. I'd rather have a compiler which claimed that good code is bad, than a

 which claimed that bad code is good. I've had crashes because of this

 and I'd rather not have any more.

Putting in a superfluous return isn't going to help you find those kind of bugs. It will just paper it over.
Aug 25 2004
parent reply Arcane Jill <Arcane_member pathlink.com> writes:
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
Aug 26 2004
parent reply "Walter" <newshound digitalmars.com> writes:
"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>.
Aug 26 2004
parent reply "Martin M. Pedersen" <martin moeller-pedersen.dk> writes:
"Walter" <newshound digitalmars.com> skrev i en meddelelse
news:cgka7p$4c2$1 digitaldaemon.com...
 Yes, you could always write a comment. The trouble with comments, though,

 they are always wrong, out of date, or missing. When examining code, I
 prefer to rely on the semantics of the language <g>.

Perhaps it would help if we had some construct that told both the fellow-programmer and the compiler, that it is an error if the program flow ever reached that point. assert(0) is traditionally used, but it is only good in debug builds. If we had a specialized construct, it would allow the compiler to perform optimizations on that basis, and we would have a way to make the compiler keep quiet about missing return values. Regards, Martin
Aug 26 2004
parent "Walter" <newshound digitalmars.com> writes:
"Martin M. Pedersen" <martin moeller-pedersen.dk> wrote in message
news:cglq6t$sad$1 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> skrev i en meddelelse
 news:cgka7p$4c2$1 digitaldaemon.com...
 Yes, you could always write a comment. The trouble with comments,


 is
 they are always wrong, out of date, or missing. When examining code, I
 prefer to rely on the semantics of the language <g>.

Perhaps it would help if we had some construct that told both the fellow-programmer and the compiler, that it is an error if the program

 ever reached that point. assert(0) is traditionally used, but it is only
 good in debug builds. If we had a specialized construct, it would allow

 compiler to perform optimizations on that basis, and we would have a way

 make the compiler keep quiet about missing return values.

That could be done, and is what Matthew proposed. But I don't see this as a big enough problem to justify adding a new keyword. Having the exception generated if one does erroneously run off the end is sufficient.
Aug 29 2004
prev sibling next sibling parent reply "Matthew" <admin.hat stlsoft.dot.org> writes:
"Walter" <newshound digitalmars.com> wrote in message
news:cghkuj$1uni$1 digitaldaemon.com...
 "Matthew" <admin stlsoft.dot.dot.dot.dot.org> wrote in message
 news:cgh9ms$1ohc$1 digitaldaemon.com...
 If D's simpler than C++ to implement, and C++ compilers can do this pretty

I've never seen a C++ compiler get it completely right, and there's no way that they can. I don't like putting in meaningless return statements in code that will never be executed and that will confuse the maintenance programmer, just to get the compiler to stop issuing an error message. But I do want to find out if that meaningless return statement ever does happen. There's no way to do it 100% without a runtime check, hence that's what the language does.

Well it's the "completely" that's the issue. I don't need 100%. In the code I write, I've maybe come across the C++ compiler not spot a missing return only a handful of types in 12 years. Conversely, I've had false positives perhaps 5 or six times a year. Frankly, I'd rather have that than missing a return. I'd far rather have the slight inconvenience of having to workaround a false positive 5 times a year than the unquantifiable and unpredictable throwing of exceptions at any time after the deployment of my code. Frankly, this is another of those situations where your penchant for compiler simplicity and the influence of your own coding style are given precedence over measures of robustness and scalability to, IMO, the long-term detriment of the language.
Aug 25 2004
next sibling parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <cght30$21u3$1 digitaldaemon.com>, Matthew says...

unquantifiable and unpredictable throwing of exceptions at any time after the
deployment of my code.

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. Arcane Jill
Aug 25 2004
next sibling parent reply "Walter" <newshound digitalmars.com> writes:
"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


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

 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
Aug 25 2004
next sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Walter" <newshound digitalmars.com> wrote in message
news:cgirt4$2fvp$1 digitaldaemon.com...
 The principle here is that, as much as practical, program bugs should

 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.

Let me expand on that a bit, because I feel strongly about this. The idea in developing robust code is to flush out bugs by making the program with the bug in it fail quickly and obviously. Inadvertantly executing statements that were never intended to be executed will likely hide bugs, making them hard to detect and harder to track down. In addition, having an assert for the missing return means that, if you run the test suite and no assert happens, you KNOW that the missing return is not executed. But if you've installed a superfluous return there, then there is NO WAY to know that the return was not executed. If you're concerned that your test suite is inadequate and your release code is therefore still buggy, and removing all the runtime checks like array bounds checking and missing return asserts will thereby cause erratic behavior, your best course of action is to leave the checks in in the shipping code. Trying to pretend the bugs aren't there by putting in superfluous code is not going to help make the released program more reliable and less buggy. As a further point, some QA processes involve instrumenting code to verify that every code path was executed by the test suite. Being forced to put in superfluous, unreachable statements throws a monkey wrench into that methodology. (One of my first major projects used such a tool, it was also probably the least buggy code I've ever done as a result. Perhaps I should add this capability to D!)
Aug 25 2004
parent Sean Kelly <sean f4.ca> writes:
In article <cgj749$2kt7$1 digitaldaemon.com>, Walter says...
"Walter" <newshound digitalmars.com> wrote in message
news:cgirt4$2fvp$1 digitaldaemon.com...
 The principle here is that, as much as practical, program bugs should

 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.

Let me expand on that a bit, because I feel strongly about this. The idea in developing robust code is to flush out bugs by making the program with the bug in it fail quickly and obviously. Inadvertantly executing statements that were never intended to be executed will likely hide bugs, making them hard to detect and harder to track down. In addition, having an assert for the missing return means that, if you run the test suite and no assert happens, you KNOW that the missing return is not executed. But if you've installed a superfluous return there, then there is NO WAY to know that the return was not executed.

I think the difference of opinion here has to do with expectations. Your way seems to expect programmers to know exactly what they're doing and to be able to test their applications fairly thoroughly for errors. The other way seems to expect that the programmer may make dumb mistakes and would like the compiler to offer more support in finding those mistakes, even though this may occasionally lead to a false sense of security.
If you're concerned that your test suite is inadequate and your release code
is therefore still buggy, and removing all the runtime checks like array
bounds checking and missing return asserts will thereby cause erratic
behavior, your best course of action is to leave the checks in in the
shipping code. Trying to pretend the bugs aren't there by putting in
superfluous code is not going to help make the released program more
reliable and less buggy.

Overall, I think your approach is more in-line with the D rationale (imagine that ;). I think it also implies that D is not a beginner's language despite its straightforward syntax, or perhaps merely that proper use of D really requires programming and testing practices not common to beginners. In some respects this makes me wish I were a CS teacher as I would be interested in seeing how folks turned out if they were taught D as a first or second language.
As a further point, some QA processes involve instrumenting code to verify
that every code path was executed by the test suite. Being forced to put in
superfluous, unreachable statements throws a monkey wrench into that
methodology. (One of my first major projects used such a tool, it was also
probably the least buggy code I've ever done as a result. Perhaps I should
add this capability to D!)

If you could do it then please do so. D's built-in support for DBC and unit testing are substantial reasons why I initially became interested in the language. If D had even more features in the testing realm it could only strengthen this selling point. Sean
Aug 25 2004
prev sibling parent reply "Matthew" <admin.hat stlsoft.dot.org> writes:
"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


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

 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".
Aug 25 2004
next sibling parent Regan Heath <regan netwin.co.nz> writes:
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 


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. 

are
 asserts, not exceptions. They vanish in a release build, leaving you 

 /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/
Aug 25 2004
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"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

 completely agree with that.

 But I also prefer *in every conceivable circumstance* to have the compile

 To me these things are completely different, and one should not be mixed

 all cases, find it at compile time, then I fail to see why D shouldn't. I

 one, in which case I prefer the assert to arbitrary behaviour. But "we

 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.
Aug 26 2004
parent reply "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"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

 completely agree with that.

 But I also prefer *in every conceivable circumstance* to have the compile

 To me these things are completely different, and one should not be mixed

 all cases, find it at compile time, then I fail to see why D shouldn't. I

 one, in which case I prefer the assert to arbitrary behaviour. But "we

 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?
Aug 26 2004
next sibling parent Arcane Jill <Arcane_member pathlink.com> writes:
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
Aug 26 2004
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Matthew" <admin stlsoft.dot.dot.dot.dot.org> wrote in message
news:cgk46j$209$3 digitaldaemon.com...
 "Walter" <newshound digitalmars.com> wrote in message

 But the compiler requiring a superfluous return statement is not finding


 bug nor is it helping find a bug. It is, often enough, hiding a bug.


 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

 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

 *explicit* documentation of the assertion/exception throw point that such

 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?
Aug 26 2004
next sibling parent "Matthew" <admin.hat stlsoft.dot.org> writes:
"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

 But the compiler requiring a superfluous return statement is not finding


 bug nor is it helping find a bug. It is, often enough, hiding a bug.


 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

 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

 *explicit* documentation of the assertion/exception throw point that such

 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.
Aug 26 2004
prev sibling next sibling parent reply Arcane Jill <Arcane_member pathlink.com> writes:
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
Aug 26 2004
next sibling parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Arcane Jill" <Arcane_member pathlink.com> wrote in message
news:cgkbn8$4pr$1 digitaldaemon.com...
 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


that there's a bug in the program, and where that bug is.

You're completely missing the point. Your statement above is obviously

 no-one is disagreeing with you. All you're doing is stating the obvious.

 it's irrelevant, so I can only assume that you're just not /getting/ what

 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

 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;
 #    }

That is exactly what i would like too. Except i would call it unreachable; :) But i could live with noreturn also. Throwing some UnreachableCodeReachedException sure is better then an assert that doesn't even exist in release and we get undefined behaviour.
 Then what is wrong with that? Furthermore, it should be a compile-time

 place any code after "return", "noreturn", "throw", "goto" or "break",

 there's a label or a right-brace. The error message should be "Unreachable

 at file xxxx line xxxx".


The noreturn
keyword would be redundant - a closing } without a return exp; for a


returning function implicitly specifies that it's an error to fall off


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


plenty?

The error message is not a problem (although it should be present in

 builds, not just debug builds). The problem is that DMD compiles code

 should not compile.

 Arcane Jill

Aug 26 2004
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
"Arcane Jill" <Arcane_member pathlink.com> wrote in message
news:cgkbn8$4pr$1 digitaldaemon.com...
 You're completely missing the point. Your statement above is obviously

 no-one is disagreeing with you. All you're doing is stating the obvious.

 it's irrelevant, so I can only assume that you're just not /getting/ what

 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

But it isn't always an error to write such code. Always diagnosing it as an error means that you have to insert superfluous return statements in that will never get executed. I've already pointed out why this is undesirable.
Aug 26 2004
next sibling parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Walter" <newshound digitalmars.com> wrote in message
news:cglfk6$mqk$1 digitaldaemon.com...
 "Arcane Jill" <Arcane_member pathlink.com> wrote in message
 news:cgkbn8$4pr$1 digitaldaemon.com...
 You're completely missing the point. Your statement above is obviously

 no-one is disagreeing with you. All you're doing is stating the obvious.

 it's irrelevant, so I can only assume that you're just not /getting/


 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

But it isn't always an error to write such code. Always diagnosing it as

 error means that you have to insert superfluous return statements in that
 will never get executed. I've already pointed out why this is undesirable.

But most of the time it is. Then add noreturn statement that will fit nicelly in the design by contarct story. In a code like this: int f(int n) { if (n == 1) return 1; noreturn; } That noreturn statement would be a contract with wich i am saying: this part of code can't/(must not) be reached. It would also be useful to see this in someone code, it would clearly document the coders intention. For example if i coded int f(int n) { if(n>0)return 1; if(n<0)return -1; noreturn; //=== throw new Exception("Unreachable code reached in f, line ..."); } And looking at this code someone would imidiatelly know my intention that n is either > 0 or <0, and that may even help someone spot a bug for example that n can be 0. With noreturn there are no superfluous returns (wich are ofcourse as undesirable as missing returns) :)
Aug 26 2004
prev sibling parent reply stonecobra <scott stonecobra.com> writes:
Walter wrote:
 But it isn't always an error to write such code. Always diagnosing it as an
 error means that you have to insert superfluous return statements in that
 will never get executed. I've already pointed out why this is undesirable.
 

You mean writing superfluous return statements like this: int someFunc() { throw new NotYetWrittenException(); return 0; //superfluous? Methinks so. Never Get executed? Absolutely } :) Scott
Aug 26 2004
parent Arcane Jill <Arcane_member pathlink.com> writes:
In article <cgln3i$qqg$1 digitaldaemon.com>, stonecobra says...

Nice one! He he he. Several <g>s and a :)
Don't you just love consistency!
Jill


Walter wrote:
 But it isn't always an error to write such code. Always diagnosing it as an
 error means that you have to insert superfluous return statements in that
 will never get executed. I've already pointed out why this is undesirable.
 

You mean writing superfluous return statements like this: int someFunc() { throw new NotYetWrittenException(); return 0; //superfluous? Methinks so. Never Get executed? Absolutely } :) Scott

Aug 26 2004
prev sibling next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Walter wrote:

 "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; ... } }

Microsoft's C# compiler handles this easily enough, but fails if the while condition is anything remotely complicated. For instance, this fails to compile: public int thingie() { int q = 0; // while (true) { // OK while (q == q) { // Not OK Console.WriteLine("q={0}", q); if (q == 4) return q; q++; } } This is more than good enough for me. If DMD were to do the same, its users would be forced to stick an "assert(false);" at the end to make the compiler happy, but I think that's fine because it is a bit more than just shutting the compiler up. The explicit annotation is useful to both people and the compiler, and, while the resulting execution flow is identical, the author is forced to be aware of the potential for a fall-off return. There is certainly the possibility that this will be forced on a programmer even when it is clear as day to him that it can never happen, but everything is clear as day when writing the code. It is, after all, the easiest part. Besides, this is exactly what the assert statement is meant for. :) -- andy
Aug 26 2004
parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <cgktoo$d5c$1 digitaldaemon.com>, Andy Friesen says...

If DMD were to do the same, its 
users would be forced to stick an "assert(false);" at the end

Almost. But # assert(false) is only equivalent to # debug # { # throw newAssertException(); # } so there is still a release-build control-path which falls straight through. This also needs to be explicitly blocked. Matthew's "noreturn" idea (or perhaps "unreachable", as has also been suggested) should be executed in both debug and non-debug builds, and so is preferable to "assert". Jill
Aug 26 2004
next sibling parent reply Dave <Dave_member pathlink.com> writes:
Arcane Jill wrote:

 In article <cgktoo$d5c$1 digitaldaemon.com>, Andy Friesen says...
 
If DMD were to do the same, its
users would be forced to stick an "assert(false);" at the end

Almost. But # assert(false) is only equivalent to # debug # { # throw newAssertException(); # } so there is still a release-build control-path which falls straight through. This also needs to be explicitly blocked. Matthew's "noreturn" idea (or perhaps "unreachable", as has also been suggested) should be executed in both debug and non-debug builds, and so is preferable to "assert". Jill

Ok, so here's how I understand the debate so far: - The compiler would catch every instance where there could be a mssing return code path, or barring that, a large amount of effort is expended to make it as accurate as possible. - The programmer could always find a way to not miss any potential return paths, and make them all meaningful, as well as not have to spend hours rearranging code to do so. Barring that, the programmer can now throw an exception at the bottom of a function and make the exception verbage as meaningful as they want. Then the 'noreturn' idea was introduced: - The compiler would check for 'noreturn' _or_ 'return ...' at the end of all code paths, making the compiler's job a bit more complicated still. - The programmer could always find a way to not miss any potential return paths, and make all paths meaningful, as well as not have to spend hours to do so. Now they would also have the choice to learn about, remember and use the non-descript 'noreturn' instruction instead of just typing a little more to throw an exception that they could make as meaningful as they want. At this point, I don't see the value of 'noreturn' over an implicit exception, because 'noreturn' wouldn't be any more expressive but would require extra compiler and programmer support. IMHO, the problem with expending a bunch of effort for a really accurate compiler is that it may well still miss the hard cases that the programmer missed in the first place (because they were hard) since it cannot be perfect. Plus the effort was expended that could have been used to make the tool better in more meaningful places, not to mention slowing down the compile speed, etc. Besides, the semantic analysis parts of C++ compilers have the advantage of many man-years and dollars worth of development under their belt. Sounds to me like we're getting little or no value for adding complexity to the language and the compiler if we start adding new "exception shortcut keywords" or diligantly try to make the compiler conform to an explicit return path spec. I think Walter is half-way to a solution now.. Halfway being checking obvious cases at compile time and doing implicit asserts for non-release builds, the other half would be implicit exceptions for release builds, _IF_ they don't screw up performance, which I think may be attainable w/o a lot of effort. - Dave
Aug 26 2004
parent reply Arcane Jill <Arcane_member pathlink.com> writes:
In article <cgl7d2$fnm$1 digitaldaemon.com>, Dave says...

- The compiler would catch every instance where there could be a mssing
return code path, or barring that, a large amount of effort is expended to
make it as accurate as possible.

It's not actually a large amount of effort. Basically, wherever you have an if(), you have to assume that there will be a path of execution for the true case, and a path for the false case. Similarly, whenever you have a switch(), you have to assume that there is a path of execution for every case, including default. Likewise, when you have a while() or a for(), you have to assume that there is a path of execution through the body, and a path which skips the body. And, you have to be aware that code which follows "return", "goto", "throw", etc., is unreachable. That's pretty much it. This approach may generate false positives, which is why Walter doesn't like it. It would mean that the compiler would say "Not all execution paths return" when a human might know otherwise. It depends whether you consider that more of a problem than the current alternative.
- The compiler would check for 'noreturn' _or_ 'return ...' at the end of
all code paths, making the compiler's job a bit more complicated still.

I can't argue with that. But in fact the compiler should (in my opinion, but not Walter's) count "throw" as equivalent to "return", in that it can be used to exit the function. "noreturn" is not very descriptive, I agree, but "unreachable" has been suggested as an alternative. As you say, it would just be syntactic sugar for "throw" with some suitable exception.
At this point, I don't see the value of 'noreturn' over an implicit
exception, because 'noreturn' wouldn't be any more expressive but would
require extra compiler and programmer support.

True. Again, it's just syntactic sugar, and it isn't really important. "throw" works for me just as well. Primarily it's Walter's "false negatives are better than false positives" philosophy with which I and others disagree.
IMHO, the problem with expending a bunch of effort for a really accurate
compiler is that it may well still miss the hard cases that the programmer
missed in the first place (because they were hard) since it cannot be
perfect.

Really accurate is hard, yes. But if you can live with false positives, you can live with a less accurate analysis. As noted above, the simple analysis is not hard.
the other half would be implicit exceptions for release builds,
_IF_ they don't screw up performance, which I think may be attainable w/o a
lot of effort.

There is no way that an unreachable throw statement can hurt performance. By definition, if it's unreachable, it will never be executed. Only if there's a bug in the code can execution ever get to that throw statement - and if there's a bug, a throw is not a bad thing. Arcane Jill
Aug 26 2004
parent Dave <Dave_member pathlink.com> writes:
Arcane Jill wrote:

 In article <cgl7d2$fnm$1 digitaldaemon.com>, Dave says...
 
- The compiler would catch every instance where there could be a mssing
return code path, or barring that, a large amount of effort is expended to
make it as accurate as possible.

It's not actually a large amount of effort. Basically, wherever you have an if(), you have to assume that there will be a path of execution for the true case, and a path for the false case. Similarly, whenever you have a

Perhaps it isn't a huge effort, but I suspect that adding another check like this to the recursive decent logic could complicate the compiler to a significant degree, because now the compiler has to keep track of more information for potentially many other recursions into other logical branches in the same function. I guess I just don't know for sure except to say that other much more mature compilers still miss, so I suspect it isn't totally straight forward.
 
 True. Again, it's just syntactic sugar, and it isn't really important.
 "throw" works for me just as well. Primarily it's Walter's "false
 negatives are better than false positives" philosophy with which I and
 others disagree.
 

Personally, I've always felt that bad data is worse than no data... Ah hell, I can see both points here.
 There is no way that an unreachable throw statement can hurt performance.
 By definition, if it's unreachable, it will never be executed. Only if
 there's a bug in the code can execution ever get to that throw statement -
 and if there's a bug, a throw is not a bad thing.

I agree - I don't think it will either, but I threw in the big IF to get the point across that it needs to be implemented efficiently ;) I held out the possibility that it could potentially cause problems. For example, if an implementation might coax the compiler into reserving scarce resources (like registers) for the call to the Exception class Ctor, and then there are the 'code distance' issues that extra code may exacerbate, etc.. I think everything except the extra bloat could be handled w/o causing adverse effects though.
 
 Arcane Jill

Aug 26 2004
prev sibling parent Andy Friesen <andy ikagames.com> writes:
Arcane Jill wrote:

 In article <cgktoo$d5c$1 digitaldaemon.com>, Andy Friesen says...
 
 
If DMD were to do the same, its 
users would be forced to stick an "assert(false);" at the end

Almost. But # assert(false) is only equivalent to # debug # { # throw newAssertException(); # } so there is still a release-build control-path which falls straight through. This also needs to be explicitly blocked. Matthew's "noreturn" idea (or perhaps "unreachable", as has also been suggested) should be executed in both debug and non-debug builds, and so is preferable to "assert".

Maybe, as a special case, assert(false) should stick around even in release mode. If it should never execute, it's not exactly in a position to cause much runtime overhead. :) Plus it saves us the hassle of setting a keyword aside for such a narrow purpose. -- andy
Aug 26 2004
prev sibling parent Sean Kelly <sean f4.ca> writes:
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. 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?

I think it is. Though I'd prefer an assert to an exception in debug builds because it would simplify debugging of the problem. And if it already works this way then I have no complaints. Sean
Aug 26 2004
prev sibling parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
"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.

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.

Bah! This just sucks then. Count me a seconder to your objections.
Aug 25 2004
prev sibling parent reply Regan Heath <regan netwin.co.nz> writes:
On Wed, 25 Aug 2004 21:27:32 +1000, Matthew <admin.hat stlsoft.dot.org> 
wrote:
 "Walter" <newshound digitalmars.com> wrote in message 
 news:cghkuj$1uni$1 digitaldaemon.com...
 "Matthew" <admin stlsoft.dot.dot.dot.dot.org> wrote in message
 news:cgh9ms$1ohc$1 digitaldaemon.com...
 If D's simpler than C++ to implement, and C++ compilers can do this 

much in their sleep, then why should D not? I've never seen a C++ compiler get it completely right, and there's no way that they can. I don't like putting in meaningless return statements in code that will never be executed and that will confuse the maintenance programmer, just to get the compiler to stop issuing an error message. But I do want to find out if that meaningless return statement ever does happen. There's no way to do it 100% without a runtime check, hence that's what the language does.

Well it's the "completely" that's the issue. I don't need 100%. In the code I write, I've maybe come across the C++ compiler not spot a missing return only a handful of types in 12 years. Conversely, I've had false positives perhaps 5 or six times a year. Frankly, I'd rather have that than missing a return. I'd far rather have the slight inconvenience of having to workaround a false positive 5 times a year than the unquantifiable and unpredictable throwing of exceptions at any time after the deployment of my code.

 Frankly, this is
 another of those situations where your penchant for compiler simplicity 
 and the influence of your own coding style are
 given precedence over measures of robustness and scalability to, IMO, 
 the long-term detriment of the language.

This is your opinion Matthew, you're entitled to it. I think you're being unfair, Walter has described his position as being _in_ favour of robustness and scalability, you simply disagree that his approach is robust and/or scalable, which is also an opinion you're entitled to. My opinion is that a middle ground could be found that would hopefully please everyone. I think if possible the compiler should catch what it can be 100% certain of at the compile stage, this step can and will improve as Walter finds examples he can catch, code that passes that step should throw an assertion at runtime in a 'debug' build as it currently does. The current behaviour of a 'release' build is ok, I believe. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 25 2004
parent Dave <Dave_member pathlink.com> writes:
In article <opsda9v8065a2sq9 digitalmars.com>, Regan Heath says...
This is your opinion Matthew, you're entitled to it. I think you're being 
unfair, Walter has described his position as being _in_ favour of 
robustness and scalability, you simply disagree that his approach is 
robust and/or scalable, which is also an opinion you're entitled to.

My opinion is that a middle ground could be found that would hopefully 
please everyone.

I think if possible the compiler should catch what it can be 100% certain 
of at the compile stage, this step can and will improve as Walter finds 
examples he can catch, code that passes that step should throw an 
assertion at runtime in a 'debug' build as it currently does. The current 
behaviour of a 'release' build is ok, I believe.

I agree that this runtime check is nice to have for debug builds regardless of how good a compiler implementation gets at catching missing returns. This may be one of those checks that could be inserted for release builds too, because if the software takes that path /once/ it dies immediately anyhow (unlike an array bounds check in a loop as an obvious example). That way there would be something for a user to report back. Could inline code with a simple message including the mangled method/function name be used for release builds?? If so then unless I'm missing some register or stack allocation issue or somesuch, it likely won't cost any performance _directly_ related to the function call, but will cost in terms of bloat regardless. Just a suggestion.. - Dave
Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/

Aug 25 2004
prev sibling next sibling parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Walter" <newshound digitalmars.com> wrote in message
news:cghkuj$1uni$1 digitaldaemon.com...
 "Matthew" <admin stlsoft.dot.dot.dot.dot.org> wrote in message
 news:cgh9ms$1ohc$1 digitaldaemon.com...
 If D's simpler than C++ to implement, and C++ compilers can do this


 much in their sleep, then why should D not?

 I've never seen a C++ compiler get it completely right, and there's no way
 that they can. I don't like putting in meaningless return statements in

 that will never be executed and that will confuse the maintenance
 programmer, just to get the compiler to stop issuing an error message.

I agree with Matthew and Arcane Jill on this. I will believe you if you say that there are some strange code fragments for wich it is not possible to detect a missing return or throw, but if D could get it right 95% of the time it would be good enough. Test only for the simplest cases with return on the end of the function or return in every branch or every case of the last if or switch and ignore those like in my example where i try to skip return with a goto. (This one can also be detected, if the last statement is empty and the one before it is a label=> error missing return at the end.)
 But I do want to find out if that meaningless return statement ever does
 happen. There's no way to do it 100% without a runtime check, hence that's
 what the language does.

Aug 25 2004
prev sibling parent reply J C Calvarese <jcc7 cox.net> writes:
In article <cghkuj$1uni$1 digitaldaemon.com>, Walter says...
"Matthew" <admin stlsoft.dot.dot.dot.dot.org> wrote in message
news:cgh9ms$1ohc$1 digitaldaemon.com...
 If D's simpler than C++ to implement, and C++ compilers can do this pretty

I've never seen a C++ compiler get it completely right, and there's no way that they can. I don't like putting in meaningless return statements in code that will never be executed and that will confuse the maintenance programmer, just to get the compiler to stop issuing an error message. But I do want to find out if that meaningless return statement ever does happen. There's no way to do it 100% without a runtime check, hence that's what the language does.

I wasn't trying to get into this debate. It's already been debated and I agree with your position. I know the compiler isn't psychic and I don't want it second-guessing every branch in my program. I was just hoping that we could have a more descriptive runtime error than: Error: AssertError Failure bug.d(7) Maybe that can't be done. I just thought it was a possibility. (It only took me a few minutes to figure out what the problem was when I ran into it, but it could have taken a lot longer if I had made more changes or had a larger program.) jcc7
Aug 25 2004
parent "Walter" <newshound digitalmars.com> writes:
"J C Calvarese" <jcc7 cox.net> wrote in message
news:cgi8mr$26f7$1 digitaldaemon.com...
 I was just hoping that we could have a more descriptive runtime error

 Error: AssertError Failure bug.d(7)

 Maybe that can't be done. I just thought it was a possibility.

 (It only took me a few minutes to figure out what the problem was when I

 into  it, but it could have taken a lot longer if I had made more changes

 a larger program.)

I agree the message isn't the best, but at least it had the file and line number <g>.
Aug 25 2004
prev sibling parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 23 Aug 2004 19:41:34 -0500, J C Calvarese wrote:

 I think I found a bug. I could be wrong. ;)
 
 bit b;
 
 int main()
 {
      if (b)
          return 0;
 }
 
 Note the lack of a return statement when b is false (which is always).
 
 It compiles fine. At runtime, an error occurs...
 Error: AssertError Failure bug.d(7)
 
 I understand it can be difficult/undesirable for the compiler to catch a 
 problem like this during compile. If the lack of a return is cause of 
 the AssertError, I hope it could at least be renamed to NoReturnError or 
 something.

Yes, a better message would be nice. Maybe "'return' expected but none was executed.". And I hope this wouldn't disappear in a "-release" build either. But meanwhile ... Should the principle for a compiler be that it tries to detect all potential errors, within practical limits, that could/would otherwise be detected at run time? I don't know the answer to this, so it is not rhetorical. <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> -- Derek Melbourne, Australia 26/Aug/04 10:14:38 AM
Aug 25 2004
parent "Walter" <newshound digitalmars.com> writes:
"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

 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.
Aug 26 2004