Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-30 Thread user1234 via Digitalmars-d

On Friday, 29 September 2017 at 09:12:54 UTC, Don Clugston wrote:

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?


There are two big family of switches. C-like and Pascal like. In 
Pascal you can only have cases in the switch.


See https://en.wikipedia.org/wiki/Switch_statement#Semantics

The C form doesn't prevent you to be stricter but it's all about 
self-discipline since the compiler will allow everything in there.


Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-30 Thread drug via Digitalmars-d

30.09.2017 05:35, sarn пишет:


For anyone who's wondering, it works because switch is just a computed 
goto.  The code's equivalent to this:


import std.stdio;

void main()
{
 int i = 0;

 // switch(i)
 if (i == 7)
 {
 goto case_7;
 }
 else
 {
 goto case_default;
 }

 // for loop initialiser
 i = 8;
 // for loop test
 while (i < 10)
 {
case_7:
 writeln(i);
 return;
case_default:
 // for loop update
 ++i;
 }
}


Thanks for clarification!


Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-30 Thread Jacob Carlborg via Digitalmars-d

On 2017-09-29 21:56, Timon Gehr wrote:


Well, I have used the switch(...) with(...) idiom you mentioned in the
original post a few times, and I'm quite confident you'd meet some
opposition if you were to break it.


I've used that as well, but the other way around. I put the switch 
statement inside the with statement.


--
/Jacob Carlborg


Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-29 Thread sarn via Digitalmars-d

On Friday, 29 September 2017 at 09:56:17 UTC, Dukc wrote:
On Friday, 29 September 2017 at 09:12:54 UTC, Don Clugston 
wrote:

Guess what this prints


My guess is it prints "1".

By "guess" I mean it, I did not test! Anyway reminds me a lot 
of very badly used gotos.


Yeah, it's a lot like Duff's Device:
https://en.wikipedia.org/wiki/Duff's_device

For anyone who's wondering, it works because switch is just a 
computed goto.  The code's equivalent to this:


import std.stdio;

void main()
{
int i = 0;

// switch(i)
if (i == 7)
{
goto case_7;
}
else
{
goto case_default;
}

// for loop initialiser
i = 8;
// for loop test
while (i < 10)
{
case_7:
writeln(i);
return;
case_default:
// for loop update
++i;
}
}



Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-29 Thread Timon Gehr via Digitalmars-d

On 29.09.2017 17:05, Don Clugston wrote:


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.
...


Oh, I see. (They look the same to me.)

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.

...


This can be done with basically any control flow construct we have:

if(i) for(i=8;i<10;++i)
{
// ...
}

(This relates to my point about consistency.)




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.


I don't see why. For example, my compiler implementation of SwitchStm 
does not mention BlockStm.



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.

...


Well, I have used the switch(...) with(...) idiom you mentioned in the 
original post a few times, and I'm quite confident you'd meet some 
opposition if you were to break it.


There's also this case:

switch(x)
static foreach(i;0..10)
static if(i==0) default: return f!0();
else case i: return f!i();

and, of course, this one:

final switch(x)
static foreach(i;0..10)
case i: return f!i();

We improved the switch statement a lot by disallowing implicit 
fallthrough.


Explicit fallthrough is still allowed though.

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.


Well, 'switch' does not uphold the principles of structured programming. 
It is natural that one can extract some silliness from that, and I don't 
think changing grammar rules in inconsistent ways in order to disallow 
particular silly examples is a very good way to design a language.


I think removing () and requiring {} everywhere as Go and Rust have done 
is quite good language design which eliminates many of C's grammar 
issues, but it is not the path that D has taken and it does not improve 
switch semantics.


Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-29 Thread H. S. Teoh via Digitalmars-d
On Fri, Sep 29, 2017 at 12:32:02PM +0200, Timon Gehr via Digitalmars-d wrote:
[...]
> 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.

I believe one of the reasons the grammar was written this way was to
allow Duff's device in D.  Personally, I don't care much for it -- an
optimizing compiler ought to be able to generate the best code without
requiring the programmer to explicitly write Duff's device.  Though
Walter did indicate that dmd's optimizer is lacking in the loop
unrolling department.


T

-- 
It is not the employer who pays the wages. Employers only handle the money. It 
is the customer who pays the wages. -- Henry Ford


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.





Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-29 Thread Timon Gehr via Digitalmars-d

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.



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).


Re: D's SwitchStatement accepts statements with ridiculous semantics

2017-09-29 Thread Dukc via Digitalmars-d

On Friday, 29 September 2017 at 09:12:54 UTC, Don Clugston wrote:

Guess what this prints


My guess is it prints "1".

By "guess" I mean it, I did not test! Anyway reminds me a lot of 
very badly used gotos.




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?