Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-29 Thread Don Clugston via Digitalmars-d

On Friday, 29 September 2017 at 10:32:02 UTC, Timon Gehr wrote:

On 29.09.2017 11:12, Don Clugston wrote:

Guess what this prints


import std.stdio;

void main()
{
   int i = 0;

   switch (i) for (i = 8; i < 10; ++i)
   {
     case 7:
     writeln(i);
     return;

     default: ;
   }
}



Why does this even compile? It's because the grammar is:

SwitchStatement:
     switch ( Expression ) ScopeStatement


and ScopeStatement allows almost anything.
I think the only sane grammar is

SwitchStatement:
     switch ( Expression ) BlockStatement

Initially I thought ScopeStatement was accepted in order to 
enable Duff's device, but it isn't necessary for that. It 
might have originally accepted ScopeStatement to support


E e; switch( e ) with (E) {  }

Or it may have just been an accident.


It is very likely that this part of the grammar was 
deliberately copied from C. It's also consistent with how all 
other control flow constructs are parsed.


But regardless of the original motivation, it allows some 
truly dreadful semantics.


I don't see what your proposed grammar change accomplishes:

switch(i){
for(i=8;i<10;++i){
case 7:
writeln(i);
return;
default:{}
}
}

I.e., you seem to have misidentified the culprit. Whether or 
not to the curly braces are required by the parser has nothing 
to do with switch semantics.


That case looks quite different to me.
It's rather more obvious that the `for` statement has been 
skipped.


The problem I have with the original example is that it looks as 
though the body of the `for` loop is the body of the switch 
statement.





Can we disallow this silliness please?



Maybe this specific case can be disallowed during semantic (but 
I don't really see why it helps, it mostly just makes the 
language definition more complex).


I believe it makes it simpler. You cannot avoid the reference to 
BlockStatement.

Note that:  "A switch statement must have a default statement."

This is only possible only in two situations.

1. Silly degenerate case.
 switch (i) default: ;

2. A statement which contains a BlockStatement.

It accepts unreachable code.

  switch (i) if ( foo() ) {} else { default: ; }

A switch statement followed by anything other than a 
BlockStatement is *always* wrong. Always.


We improved the switch statement a lot by disallowing implicit 
fallthrough. But it still allows other nonsense that was 
presumably inherited from the very early days of K&R C.


This example just struck me as exceedingly silly, and quite 
misleading.





D's SwitchStatement accepts statements with ridiculous semantics

2017-09-29 Thread Don Clugston via Digitalmars-d

Guess what this prints


import std.stdio;

void main()
{
  int i = 0;

  switch (i) for (i = 8; i < 10; ++i)
  {
case 7:
writeln(i);
return;

default: ;
  }
}



Why does this even compile? It's because the grammar is:

SwitchStatement:
switch ( Expression ) ScopeStatement


and ScopeStatement allows almost anything.
I think the only sane grammar is

SwitchStatement:
switch ( Expression ) BlockStatement

Initially I thought ScopeStatement was accepted in order to 
enable Duff's device, but it isn't necessary for that. It might 
have originally accepted ScopeStatement to support


E e; switch( e ) with (E) {  }

Or it may have just been an accident.
But regardless of the original motivation, it allows some truly 
dreadful semantics.

Can we disallow this silliness please?



Re: Exception chaining and collectException

2017-08-18 Thread Don Clugston via Digitalmars-d

On Friday, 18 August 2017 at 03:31:38 UTC, Walter Bright wrote:
Chained exceptions are a good idea, but are more or less a 
disaster:


1. No other language does chained exceptions

2. Attempting to hammer D chained exceptions into other 
language schemes (such as C++) makes for lots of unfun hours 
attempting to decode undocumented behavior in those other 
schemes


3. Makes D exceptions incompatible with other language 
exceptions and their infrastructure


4. Are incomprehensibly implemented (I defy anyone to explain 
how the test cases in the test suite are actually supposed to 
work)


Well, I wrote them, so I can explain that. The problem is that 
the idea that you can form a "chain" of exceptions turns out to 
be naive.


What if a chained exception needs to get chained to another 
chained exception? And that then needs to be chained to another 
exception?

It forms a tree! That's why the test cases are so complicated.

So to a large extent, this extremely obscure corner case destroys 
the elegance of the concept.


Secondly, exception handling in windows is practically 
undocumented. Certainly it's not documented in a single place. 
When I began to implement it, I feared it might be impossible. 
There isn't any guarantee that exception chaining can actually be 
implemented on all platforms.



5. Are more or less incompatible with non-GC memory allocation

I'd like to remove them from D.

I recommend *not* designing any program that requires them.


I invested quite a lot personally in implementing chained 
exceptions. But I agree with you.
I was actually quite proud that I worked out the nasty corner 
cases during the initial implementation. As far as I can tell, 
problems with chained exceptions are not because of bugs and 
implementation issues, but because of problems with the concept 
itself.


I think it's just a bit too clever.