December 09, 2003
Uh uh uh...

The compiler _does_ require good practices (in your opinion) or, in my opinion, bad practices in some cases.

e.g.
if ( x = y )
which is flagged by the compiler and needs to have more code added to tell the
compiler that that is what I meant -- _that's bad_ !

And, even worse, it breaks ported C code as well.

In article <br3uce$1cvu$1@digitaldaemon.com>, Walter says...
>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.
>


December 09, 2003
In article <br3s0u$19rs$1@digitaldaemon.com>, Walter says...
>> 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.

Yes I would view the switch statement the same way.

There are three ways of looking at this.

1) No 'default' means that all other values are an error.  The programmer should explicitly state that other values are not an error condition by putting default: break;

2) No 'default' means that other values are acceptable.
The programmer must explicitly state that other values
are an error condition by putting default: assert(0);

3) 'No default' is a compiler error.  The programmer must explicitly state how other values are handled.

As far as explicitly stating the programmers intention
all three work equally well when combined with firm
documentation of the default behavior of the switch
statement.  All that option 3 really does is save the
programmer from an error of omission.  In other words
the programmer really intended the opposite behavior
from what the default is but forgot to include the
'default' statement.  How is this  any different that
any other error of omission?  Are you more likely to
forget a 'default' in a 'switch' than a 'else' on a
'if'?

Now as for choosing between options 1 and 2.  It makes sense to me that a switch lists the values that are handled, not the values that are not handled.  So if a value is not in the list it is an error.  'default' means I handle every other value not explicitly listed.

As for throwing a runtime error for the implicit default case it is really very similar to the runtime error for an array index out of bounds. I don't have any problem with this behavior.

So I'm voting for Walter's current implementation.






December 09, 2003
This probably wont help any but a switch that acts like visual basics Select
Case statement would be the my preferred method.
Select Case Acts like so:

Select Case Foo

Case 1
DoSomething()

Case 2,3,4,5
DoSomething()

Case 10
DoSomething()

Case Else
Nothing Was Caught So Do A Default

End Select

What happens, is that it falls down thru till a match is found, an that matching statement is then executed... if nothing is found, the Case Else is excecuted. The Case Else is optional, so if nothing is matched, nothing is excecuted.


December 09, 2003
Berin Loritsch wrote:
> If a method will throw a known exception I want something stronger than a
> comment to tell me about it.
> 
> Things that are inadvertant errors such as illegal argument exceptions,
> bounds checking exceptions or other obvious runtime exceptions, then I don't
> want to know about them or worry about them.  I think having a mix of both
> checked and unchecked exceptions provides a nice way to ensure things are
> working properly--within reason.

That won't suffice. The main problem I have with JAVA's forced throws clause is that it prevents proper use of interfaces. (There are other flaws, like the insane amount of throws clauses you get if the call hierarchy gets deep enough, but the interface problem is the most important one to me.)

The main point in having interfaces is to abstract from the implementation. But if you have to define what kinds of errors can occur in the implementation, then you automatically limit the "back-ends" you can put behind it.

A great example is if you want to implement an existing interface to forward calls over a network to a server and let the server perform the task. Suddenly there are a whole lot of additional errors, like "host not found", "connection lost" and stuff like that that were not anticipated by whoever wrote the original interface.

So what you end up with is either ignoring such errors or wrapping them in an object of one of the "legal" classes. Both ways are bad. The first one hides errors and can have serious consequences for the ability of the program to work properly. The second one defeats the whole purpose of having different exception classes, as they often end up being wrapped in some unrelated exception type.

After having been frustrated with this "feature" of JAVA multiple times I just decided to ignore it for my last project. In that program EVERY method has a "throws Exception" clause. I was just fed up with trying to keep up meaningful error handling in an interface-based program while the compiler was working against me.


Hauke
December 09, 2003
"The Lone Haranguer" <The_member@pathlink.com> wrote in message news:br58dg$gms$1@digitaldaemon.com...
> C has an implicit default:break; ?

Yes.

> Regardless, as I don't like your built-in assert(), I certainly don't want
the
> compiler to add one.
>
> Why do you insist on not breaking ported C code in some cases, while going
out
> of your way to break it in other cases? Make up your mind!

I plead guilty to the inconsistency.


December 09, 2003
Patrick Down wrote:
> There are three ways of looking at this.
> 
> 1) No 'default' means that all other values are an error.  The programmer should explicitly state that other values are not an error condition by putting default: break;
> 
> 2) No 'default' means that other values are acceptable.
> The programmer must explicitly state that other values
> are an error condition by putting default: assert(0);
> 
> 3) 'No default' is a compiler error.  The programmer must explicitly state how other values are handled.  
> 
> As far as explicitly stating the programmers intention
> all three work equally well when combined with firm documentation of the default behavior of the switch statement.  All that option 3 really does is save the programmer from an error of omission.  In other words the programmer really intended the opposite behavior from what the default is but forgot to include the 'default' statement.  How is this  any different that any other error of omission?  Are you more likely to forget a 'default' in a 'switch' than a 'else' on a 'if'?

There is one important difference: it works differently in all other major languages. I programmed in C, C++ and JAVA for many years and I fear that I WILL forget to put that default in there. D's syntax is so similar in many respects and the construct even has the same name! So this is an accident waiting to happen.

But the worst thing about this is that when that accident happens I might not know it until it is too late (i.e. when the application is shipped and some user has done something that causes the default case to trigger).

That's why I prefer the explicit default. No matter what you think is intuitive (and we have seen that this IS different from person to person), the compiler will warn you right when you made your mistake. Then you just type an additional line and there's no harm done. Compare that to the case where I have to find the bug after a user has told me "Your software thingy crashed! I didn't do anything!".

Hauke
December 09, 2003
Walter wrote:

> While I generally agree with you here, the point I make is that the language
> should make the right thing to do the easiest thing to do. In Java, the
> right thing to do with checked exceptions is the most tedious thing to do.
> The easiest thing to do in Java is just do a catch(...) and forget about it.

You don't need the experts to tell you that. I just took 2 randomly bought Java books from my bookshelf, and discover that they both teach the same practice... One being "Java 2 Wochenend Crashkurs" (MITP) and another "Java 2 Kompendium" (Markt&Technik). I believe the second is quite popular out here...

And if the novices are not taught to get it right from beginning on, they probably realize that it's wrong when it's much too late.

I'm somewhat thankful to parts of the library which don't force declaring eceptions on me... BTW, i've been rethinking my strategy about warnings ("nags")... I think now i'm more or less with you.

The major difference to other warnings is though, that it is requiered to add these "throws" specifications not on one functiones, but on all which possibly can call it, including indirect calls, and that's what makes throw specification so evil. The number of changes requiered explodes with the growing project size. Change the underlying implementation of one function, so that the part of the library it uses may throw another exception, and there you have it - go ahead and correct the whole call tree. My current solution would be, to catch these exceptions with an assert if i don't expect them anyway...

-eye



--- rant --- 8< ---
come to think of it, i don't know of a single Delphi book to teach questionable practices. however, C++ and java books teaching bad practice are quite common... while with c++ it is somehow explained by complexity - which is imo just a bad excuse for being unable to write a good book, or to get hands on writing a book for *novices* without understanding the language - for java it's really incredible... everyone knows, we should not do this and that, but we do and teach it anyway... that's where i can say the language is flawed... maybe another reason for good Delphi books is that they had to rival with the comprehensive, thought-through, wise manual (actually a tutorial book) delivered with each Delphi package? all delphi books seem to share a ton of similarity with that original work... something we should think about when it comes to our manuals someday.
--- >8 ---

December 09, 2003
Lewis Miller wrote:

> This probably wont help any but a switch that acts like visual basics Select
> Case statement would be the my preferred method.
> Select Case Acts like so:
> 
> Select Case Foo
> 
> Case 1
> DoSomething()
> 
> Case 2,3,4,5
> DoSomething()
> 
> Case 10
> DoSomething()
> 
> Case Else
> Nothing Was Caught So Do A Default
> 
> End Select
> 
> What happens, is that it falls down thru till a match is found, an that matching
> statement is then executed... if nothing is found, the Case Else is excecuted.
> The Case Else is optional, so if nothing is matched, nothing is excecuted.
> 
>
This is my preferred style as well.  (Maybe it's from all of my experience in VB/VBA.)

It handles the cases I ask it to handle.  That's enough for me.

Justin
December 09, 2003
In article <br5b9g$l4b$1@digitaldaemon.com>, Lewis Miller says...
>
>This probably wont help any but a switch that acts like visual basics Select
>Case statement would be the my preferred method.
>Select Case Acts like so:
>
>Select Case Foo
>
>Case 1
>DoSomething()
>
>Case 2,3,4,5
>DoSomething()
>
>Case 10
>DoSomething()
>
>Case Else
>Nothing Was Caught So Do A Default
>
>End Select
>
>What happens, is that it falls down thru till a match is found, an that matching statement is then executed... if nothing is found, the Case Else is excecuted. The Case Else is optional, so if nothing is matched, nothing is excecuted.
>
>

I must agree with this approach.  This, to my mind, is the right way (TM) to do
switches/cases/selects.  The C'ish approach smacks of hackery and danger
(dangery?  hackanger?).

I've been working in a language other than C/C++ for ~2 years now professionally (game development, native code compiled language), and while it does resemble C++ in many ways, it implements switches as above.  I must say I don't miss C's questionable switches *at all*. They seem quite bad to my mind, and I'm glad to have moved away from them.

(hmm... what's this dead horse doing here?)

Fall-through is bad! You never *ever* need it. If you reexamine all your switch statements in your own code and think of how they'd be done if fall-through were not allowed, I believe you will find that you could write clearer code once you've made the paradigm shift. Fall-through's are treacherous short-cuts and are bugs waiting to happen. They do not belong in a language that is attempting to increase code safety.

The reuse of the 'break' keyword is confusing at best, and significantly dangerous at worse (see http://www.cs.berkeley.edu/~nikitab/courses/cs294-8/hw1.html for an example where a programmer expected the 'break' in a 'switch' to break out of an enclosing loop, causing a telephone system failure that ran up a $60 million loss).  'Break' should mean only one thing!   Switch statements cases should break implicitly. Cases should be stackable as above to account for handling multiple cases exactly the same way.  Goto's, explicit fall-throughs, and other sleights of hand are extra.  C# is blazing the way, we must merely follow.

(I bet that dead horse will think twice next time!)

As for requiring a 'default' case, I think that is an extreme response to a specific problem.  It really looks no different (to my eyes) than requiring an 'else' for every 'if'.

Throwing an exception when a case isn't handled *will* force programmers to write safer code in general, but the cost is not insignificant.  I can see both sides of this issue so I'll defer to Walter for the force of the argument.

There, I've had my rant  :)

Dan L.


December 10, 2003
Walter wrote:
> "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.
> 
> 
Walter,

OK, I disagree with the current switch statement mostly in ways that are diametrically opposed to the opinion of Matthew Wilson, but I'm going to support his arguments since I see it as the lesser of "two evils" (so to speak):

*Let's require a case on each switch statement.*


This is better than the current situation of "random runtime errors" that I have.

I'll come out and say it:  I usually don't cover all of the case.  I don't want to cover them all.  (Oh, no!  I must be a bad programmer.) If I'm reading in a simple little configuration file for a simple little application, I don't want a runtime error because the user puts an unknown setting in a line.  I'll just ignore it.  So I put "default: break;" at the end of the switch.

So I'd rather D complain about it at compile time to remind me to add my "default: break;" and you and Matthew will remember to add your "default: assert(0);"

If the errors are comping to occur due to my style of programming, I'd prefer them to appear at compile time when they're less embarrassing.


(Of course, I'd argue going the opposite direction tommorrow -- hands-off compiling/no runtime checking -- if you show any signs of softening up on that idea.)

Justin