December 09, 2003
"Sean L. Palmer" <palmer.sean@verizon.net> wrote in message news:br040i$1mqc$1@digitaldaemon.com...
> I thinkWalter's way is better than not checking at all, but a few people
on
> this NG (including me) think it would be even better if the compiler just complained at you that not all the cases were handled.

This is equivalent to requiring that an explicit default statement always be provided. There's no way the compiler can prove all cases were handled.

> If the compiler can
> tell that there are possible input values that aren't handled, it should
> require a default clause.

There's just no way for the compiler to do this.

> I do not believe that enums that were typecasted
> from ints should be considered.  If there is an error converting int to
enum
> it should be exposed at the point of the cast, not worried about during a later switch.

Casting ints to enums should not be an error. Consider, for example, gathering input from a data file and converting it to an enum. If the cast is made illegal, then the programmer will just do it another way, such as type painting or using an enum. Other values can also creep in from coding bugs elsewhere, pointer bugs, etc.

> switch (value)
> {
>     case 1:
>         blah();
>         break;
>     case 2:
>         foo();
>         break;
>     case 3:
>         bar();
>         break;
> }
>
> Now what the programmer *probably* meant was that if you get 1,2, or 3, do those things, otherwise do nothing.  But it's not explicit in the code.
We
> would want it to mandatorily be explicit.

I view the above switch statement as explicitly saying "the only possible values for value are 1, 2 or 3. No other values are possible. Therefore, it is a program bug if there are any other values." This also means the D optimizer is allowed to take advantage of the knowledge after the end of the switch that value can only have the values 1, 2, or 3. If an explicit default is given, that means that other values are possible.

> Then if you want an assert, you put an assert, and if you do not,
expecting
> C's rules to hold, you don't get burned by asserts thrown once your application ships, especially if the assert is thrown in a situation that otherwise would be perfectly gracefully handled (because you really *did* mean that if the case isn't matched, it should do nothing.)

The throwing of the switch default exception is not causing a bug in the program. It is detecting a bug in a manner that is more reasonable than the random, erratic behavior caused by unanticipated input. DM compilers are loaded up with such runtime checking; I'm sure you're all familiar with the messages it produces! I'm sure you've also noticed that the compiler rarely crashes as a result of a bug, it usually semi-gracefully quits with an internal error message. I much prefer the latter to the former.

> Anytime there is a runtime check, there is a bug waiting to happen.

I don't agree, since I think it's equivalent to saying that stripping all error checking code out of a program will improve its reliability. The whole idea of Design by Contract is to validate various assertions about the state of the program. Invalid states are supposed to cause the program to terminate gracefully. Unanticipated values in a switch statement certainly are an invalid state of the program, and checking for them is a (small) part of DbC.

> Make it
> so you don't need the check, and there is no possibility of a bug at all.
> That's better.

I certainly agree with that. But I think that is not our point of disagreement - our disagreement is whether the runtime check should be put in by the programmer or by the compiler. If you explicitly insert default:assert(0); there's still a runtime check! I'll reiterate that there's no way that the compiler can prove that all cases are covered without a default statement.

You have an excellent point that the semantics differ from C, where the implicitly generated default statement is default:break; rather than default:assert(0);. Interestingly, from a code generation perspective, you can save a bit of space and time by having no default case at all. This is possible in D (it is not possible in C) when compiled with runtime checking turned off.


December 09, 2003
"Matthew Wilson" <matthew.hat@stlsoft.dot.org> wrote in message news:bqjqtl$18hg$1@digitaldaemon.com...
> "Walter" <walter@digitalmars.com> wrote in message news:bqitol$2va4$1@digitaldaemon.com...
> >
> > "Matthew Wilson" <matthew.hat@stlsoft.dot.org> wrote in message news:bq8cg7$30ro$1@digitaldaemon.com...
> > > > Why is providing a runtime check that all the bases were covered
make
> a
> > > > program less robust?
> > > Anything that pushes out error-detection from (where it is achievable,
> of
> > > course) compile-time to runtime loses robustness. Isn't that
axiomatic?
> >
> > It's not achievable at compile time, regardless of whether the default
is
> > inserted by the compiler or the programmer.
>
> Why not?

Casting, unions, pointers, reading data from files, inline assembler, external functions, buffer overflows overwriting the stack with a virus(!), etc. All kinds of ways to have random bit patterns in an otherwise constrained repository for a type. Just the kinds of problems DbC should help catch <g>.


December 09, 2003
"Matthew Wilson" <matthew.hat@stlsoft.dot.org> wrote in message news:bqjqtm$18hg$2@digitaldaemon.com...
> "Walter" <walter@digitalmars.com> wrote in message news:bqj778$bkj$1@digitaldaemon.com...
> > "Ant" <Ant_member@pathlink.com> wrote in message news:bqj3b0$5vc$1@digitaldaemon.com...
> > > You are contradicting your self because you are forcing programers to have a "defaul:assert(0);". even if they don't know about it!
> > But D doesn't force them to explicitly write it! Sorry if I wasn't clear about that.
> So what? It does force them to have it.
> This is so bogus. You are forcing something on people that probably a lot
of
> them do not want. How is that in keeping with the philosophy of not
forcing
> things on people?
> Which is more odious, a forced compile-time restriction, or a forced
runtime
> restriction?

I think both are odious for the switch, so as with all the runtime checks, they are not generated when compiled with -release. Though if one doesn't have a good test suite, it might be a good idea to not use -release and leave the runtime checks in.


December 09, 2003
"Matthew Wilson" <matthew.hat@stlsoft.dot.org> wrote in message news:bqjr7a$197c$1@digitaldaemon.com...
> Ok, I can (hopefully) see where you're not understanding our argument. AFAICT no-one's arguing for a C status-quo, which is what all your
arguments
> seem to be addressing.

So, we all agree that C's implicit default:break; is not what we want? (This may cause some C code ported to D to have problems crop up. I think this is bearable, I just want to make sure it is known.)

Does this also mean we agree that throwing a runtime exception on the default is not a bad thing if it is intended that cases cover all the bases?

> Put in its simplest form: we want the compiler to
> force us to write a default, *in all cases*.

If this is our only point of disagreement on this, I don't think it's worthy of all the heat!

> My previous suggestion was to
> enable the syntactic sugar of substituting "unexpected:" for "default:
> assert(0);". (Note that "unexpected:" would throw something a little more
> informative than assert(0), perhaps an UnexpectedCaseException?)

Actually, it throws a SwitchError exception, giving file name and line number.


December 09, 2003
"Andy Friesen" <andy@ikagames.com> wrote in message news:bqk3hl$1ldp$1@digitaldaemon.com...
> Walter wrote:
> > It's very, very important that programs fail in a controlled manner when they encounter unanticipated conditions.
> Nondeterministic bugs are great for burning a few hours (and brain cells)

Yup. That's why DbC is so valuable, as the earlier in the program the bug is detected the more likely it is deterministic.


December 09, 2003
"Lars Ivar Igesund" <larsivar@igesund.net> wrote in message news:bqk56n$1o0g$1@digitaldaemon.com...
>
> "Walter" <walter@digitalmars.com> wrote in message news:bqjanc$gfp$1@digitaldaemon.com...
> >
> > It's very, very important that programs fail in a controlled manner when they encounter unanticipated conditions.
> >
>
> I might accept your solution if you make a minor change. Don't use
> assert(0);!

I apologize for speaking metaphorically, what actually happens is not an assert(0) but a SwitchError exception is thrown. It'll give the file and line number, too, so it shouldn't be hard to find where it's coming from.

> The exception thrown MUST be a well documented and well
> specified exception (like the UnknownSwitchCaseException suggested
> by Matthew).

I agree. And the documentation says: "If none of the case expressions match, and there is not a default statement, a SwitchException is thrown." www.digitalmars.com/d/statement.html#switch. <g> (Actually, the documentation is wrong, it's now a SwitchError.)

> Even better, demand the default case at compile time. Then it will never be a problem at runtime!

I'm reluctant to do that from experience with Java's demands that all exceptions be handled. The result was people would just blindly insert catch(...) to shut up the compiler. The result was *worse* because now new exceptions that *needed* to be dealt with got silently swallowed. (I've had some long discussions with well-known Java gurus about this.) It was one of those things that looked great on paper, but failed in practice.


December 09, 2003
"J C Calvarese" <jcc7@cox.net> wrote in message news:bqlash$d74$1@digitaldaemon.com...
> <rant>
> Good programming practices can be encouraged by the language.  Good
> programming practices can't be compelled.  As the rules of a language
> approach compelling good practices, it would become unusable before it
> reached that apex.
>
> If I'm wrong on this, please tell me which language compels good
> practices, and tell me how much you like developing in that language.
>  From my perspective, the only safe language for me is the one that I
> don't use.
> </rant>
>
> I'm not trying to be obnoxious; this is just the way I look at it.

I actually agree with you. D doesn't compel you to use good practices. Nowhere does D require you to use in and out contracts, class invariants, eshew pointers, etc. What it *does* do is provide facilities to make it easier to use the good practices than the bad ones.

For example, using an out parameter is a better practice than passing an explicit pointer to the parameter.

For another example, D lets you write quick and dirty programs that do no error checking on things like file open failures, disk write failures, etc. If such an error actually does happen, though, you get a nice message and the program terminates gracefully. This is quite unlike C, where if you forget to check for file open failures you're likely to get a seg fault, a hang, or other gloriously bad behavior.

D is well suited to writing both quick-and-dirty programs as well as careful, thorough programs. I bet a lot of us write numerous one-shot dumb little utility quick-and-dirty programs (I know I do). There's a balance to be struck between a helpful compiler message and an annoying nag. Each of us obviously would want to draw that line in a slightly different place, but hopefully those lines aren't too far apart.


December 09, 2003
"Berin Loritsch" <bloritsch@d-haven.org> wrote in message news:bqks57$2pa4$1@digitaldaemon.com...
> The use of the "assert(0)" as the default "default" clause is not really my beef.  What I really want is to know exactly where the error happened.  I can't know that if all I get is "Assertion Error" from the application.  I need a stack trace to find out where this assertion happened.  What would be even better is to use a better typed exception like this:
>
> default: throw new UnexpectedCaseException(caseValue);
>
> That way we can output the caseValue, an exception that makes sense. But even more important some very basic debug info like where the stinkin' exception was thrown is imperitive.

I agree. This is what D already does:

C:\>type test.d

void main()
{
    switch (3)
    {
        case 1: break;
    }
}

C:\>dmd test
Max # of fixups = 4
\dm\bin\link test,,,user32+kernel32/noi;

C:\>test
Error: Switch Default test.d(4)

C:\>


December 09, 2003
"Berin Loritsch" <bloritsch@d-haven.org> wrote in message news:bqfiuc$vsf$1@digitaldaemon.com...
> Walter wrote:
> > Several C++ compilers do emit warnings for such. I find those warnings
to be
> > irritating rather than useful. For example, they will warn about:
> >
> >     int foo()
> >     {
> >         while (1)
> >         {
> >                 ....
> >                     return ...;
> >         }
> >     }
> >
> > where it is *not possible* for the code to fall off the end, but the
warning
> > happens, and to get rid of it I have to put in a return statement that
will
> > never execute. I find being forced to add code that will never execute
to be
> > inelegant and potentially confusing. Hence my motivation for having D
ensure
> > that it never executes by raising an exception if it does, but that
doesn't
> > muck up the source code.
> There are a couple things I really don't like about that code anyway.  For instance, it is usually bad practice to return from inside a loop--

It must be supported even if it's bad practice.

> your language
> has to be very good at cleaning up its stack in these cases.

It isn't any extra work for the code generator <g>. The ugly problems are having returns inside try, finally or catch blocks.

> Second, if you
> want to loop forever until something important happens, use while(true)
instead
> of a number.  Explicit booleans can make conditionals absolutely clear.

Ironically, some other compilers I use complain about any use of while with a constant, whereas the blessed form of an infinite loop is for(;;). Every team seems to have a different view of the right way to do an infinite loop; I prefer while(1) because there's no way that some idjit #define'd true to be 0. (And yes, in the old C days, you would find such definitions of true.) And yes, in D true is a keyword and can't be mucked up that way, but old habits die hard <g>.

> Lastly, if you want to break a loop early, that is what the break keyward
is
> for. Anyhoo, I really don't like that snippet above for my own sense of
code style
> purposes.  It really isn't that clear.

Perhaps not, but these snippets I post are the essence of some considerably longer piece of code. I remove all the irrelevant cruft to get a minimalist example. This sometimes results in a snippet few people would actually write, but what I'm doing is trying to illustrate something that should be handled correctly by the compiler, not advocating it as good style.

> I have read in many places that it is much better to have the principle of
one
> place of exit.

You're right that there are many people who carefully follow the one exit rule. It is a perfectly reasonable style. But D isn't trying to enforce a particular style, it needs to be an easy migration path from C and C++ code, and such code uses returns in all kinds of weird places. If D forced a one exit rule on them, the potential users for D would shrink significantly.


December 09, 2003
I agree, esp. with the last point. Things are a lot clearer for me now. So, no "default" case required.


In article <br3t6m$1bd1$1@digitaldaemon.com>, Walter says...
>
>
>"Lars Ivar Igesund" <larsivar@igesund.net> wrote in message news:bqk56n$1o0g$1@digitaldaemon.com...
>>
>> "Walter" <walter@digitalmars.com> wrote in message news:bqjanc$gfp$1@digitaldaemon.com...
>> >
>> > It's very, very important that programs fail in a controlled manner when they encounter unanticipated conditions.
>> >
>>
>> I might accept your solution if you make a minor change. Don't use
>> assert(0);!
>
>I apologize for speaking metaphorically, what actually happens is not an assert(0) but a SwitchError exception is thrown. It'll give the file and line number, too, so it shouldn't be hard to find where it's coming from.
>
>> The exception thrown MUST be a well documented and well
>> specified exception (like the UnknownSwitchCaseException suggested
>> by Matthew).
>
>I agree. And the documentation says: "If none of the case expressions match, and there is not a default statement, a SwitchException is thrown." www.digitalmars.com/d/statement.html#switch. <g> (Actually, the documentation is wrong, it's now a SwitchError.)
>
>> Even better, demand the default case at compile time. Then it will never be a problem at runtime!
>
>I'm reluctant to do that from experience with Java's demands that all exceptions be handled. The result was people would just blindly insert catch(...) to shut up the compiler. The result was *worse* because now new exceptions that *needed* to be dealt with got silently swallowed. (I've had some long discussions with well-known Java gurus about this.) It was one of those things that looked great on paper, but failed in practice.
>
>