February 17, 2014
On Sunday, 16 February 2014 at 15:43:31 UTC, Manu wrote:
> So D offers great improvements to switch(), but there are a few small
> things I wonder about.
>
> 1.
> case fall-through is not supported; explicit 'goto case n;' is required.
> With this in mind, 'break' is unnecessary. Why is it required? It could be
> implicit upon reaching the next case label, or a scope could be used (with
> support for omitting the scope for single statements as with if).
> It's really noisy, and annoying to write everywhere.
>
> 2.
> 'case 1, 3, 7, 8:' is awesome! ...but ranged cases have a totally different
> syntax: 'case 1: .. case 3:'
>
> Why settle on that syntax? The inconsistency looks kinda silly when they
> appear together in code.
> Surely it's possible to find a syntax that works without repeating case and
> ':'?
>
> It's also weird, because it seems that 'case n: .. case m:' is inclusive of
> m. This may be unexpected.
> I'm not sure it's reasonable to use the '..' syntax in this case for that
> reason. '..' is an [) range, case ranges must be [] so that it makes sense
> when dealing with enum key ranges.
>
> 3.
> Why is 'default' necessary? If I'm not switching on an enumerated type,
> then many values are meaningless. requiring an empty 'default: break;' line
> at the end is annoying and noisy.
>
> I often find myself tempted to rewrite blocks of successive if() logic
> comparing integers against values/ranges, but it looks silly since the
> scope rules are not explicit, and 'default: break;' always wastes an extra
> line.
> I like to reduce noise in my code, and these switch semantics threaten to
> simplify a lot of code, if not for these strange decisions (purely for
> legacy compliance?).
>
>
> Let's consider an example:
>
> Code like this:
>
> int difficulty = -1;
> if(e.note.note >= 60 && e.note.note < 72)
> difficulty = 0;
> else if(e.note.note >= 72 && e.note.note < 84)
> difficulty = 1;
> else if(e.note.note >= 84 && e.note.note < 96)
> difficulty = 2;
> else if(e.note.note >= 96 && e.note.note < 108)
> difficulty = 3;
>
> The repetition of e.note.note is annoying, and particular choice of
> comparisons are liable to result in out-by-ones. It's not nice code to read.
>
>
> Rewrites like this:
>
> int difficulty;
> switch(e.note.note)
> {
> case 60: .. case 71:
> difficulty = 0;
> break;
> case 72: .. case 83:
> difficulty = 1;
> break;
> case 84: .. case 95:
> difficulty = 2;
> break;
> case 96: .. case 107:
> difficulty = 3;
> break;
> default:
> difficulty = -1;
> break;
> }
>
> That's horrid, it's much longer! And there are pointless wasted lines
> everywhere.
> The default case is a total waste, since -1 should just be assigned when
> initialising the variable above.
>
>
> We can compact it a bit like this:
>
> int difficulty;
> switch(e.note.note)
> {
> case 60: .. case 71:
> difficulty = 0; break;
> case 72: .. case 83:
> difficulty = 1; break;
> case 84: .. case 95:
> difficulty = 2; break;
> case 96: .. case 107:
> difficulty = 3; break;
> default:
> difficulty = -1; break;
> }
>
> But that's horrible too. It's not clear what vertical offset the 'break'
> statements shoudl appear at (I hate stacking up multiple statements across
> the same line!).
> The the default case is still a waste.
>
>
> Ideally:
>
> int difficulty = -1;
> switch(e.note.note)
> {
> case 60 .. 72:
> difficulty = 0;
> case 72 .. 84:
> difficulty = 1;
> case 84 .. 96:
> difficulty = 2;
> case 96 .. 108:
> difficulty = 3;
> }
>
> 'break's are unnecessary since fallthrough isn't allowed.
> Proper numeric range could be supported (assuming [) intervals).
> 'default' case is unnecessary, and removed.
>
> The switch and braces results in 3 extra lines, but I still feel this level
> of simplification results in code that is MUCH more readable than the
> sequence of if's I started with. It's super obvious what's going on.
>
> I have quite many blocks like this.
>
> A great man once (actually, frequently) said "If it doesn't look right, it
> probably isn't".


Having also wrote a lot of switch statements in D I do mostly
agree on these points. I think this example 'case 1: .. case 3:'
is obvious. but I like 'case 1..3, 5, 6, 8, 9..10:' syntax better
(Pascal) see how much typing I save.

Break inside a switch should be rid of (Again Pascal) it's bloat.

Having a default does get a bit annoying I see a lot of these..
That being said it's nice having that extra safety.
February 17, 2014
On Monday, 17 February 2014 at 04:00:08 UTC, Manu wrote:
> Of course, I'd just write the above as:
>>
>> int difficulty = e.note.note.between(60,108) ? (e.note.note-60)/12 : -1;
>>
>
> Yes yes, very clever. Obviously it's an example and could come in any shape
> or form.
> Personally, I also wouldn't do that anyway; basic readability has
> definitely been lost.


I know I'm weird here, but I disagree. I had no idea what you were doing at the beginning of the topic, but that one line revealed to me that this is likely related to the music game thing you proposed awhile ago. I can't really explain why "note" was insufficient before to reveal that, but once I saw "12" explicitly on its own I immediately thought ~"12 ... semitones ... octaves ... note ... it's music ... he was working on a music game ... he came up with this while working on the music game".

So, it's classifying difficulty based on which octave a note is for your music game?

Of course, I might be wrong here. It just seems to me that the reducing of information made it clearer what the purpose is disregarding the other contextual information that probably exists outside of what you're trying to show us.
February 17, 2014
On 17 February 2014 16:18, Andrei Alexandrescu < SeeWebsiteForEmail@erdani.org> wrote:

> On 2/16/14, 7:42 AM, Manu wrote:
>
>> So D offers great improvements to switch(), but there are a few small
>> things I wonder about.
>>
>
> TL;DR of my answer to this: at some point we must get used to the notion that minute syntax tweaks are always possible that make us feel we're making progress when instead we're just moving the rubble around.
>

OT: Do you realise how harsh your posts often appear to people? I often find I need to restrain myself when replying to your blunt dismissals of peoples opinions/suggestions.

So, you admit that this is a disaster site, but are reluctant to consider
what good may come of it?
I'm not suggesting to move the rubble around a bit, I'm suggesting a missed
opportunity to build something new and useful from the rubble.

There are like, 5 control statements in the language; if, for, while,
foreach, switch. To trivialise their importance is surprising.
switch is basically the same in D as in C, which kinda finds a purpose here
and there, but it's built on a rubbish foundation. I can imagine switch (or
something like it) being _extremely_ useful to address whole new classes of
problems (like match in rust and others) if it were just a little bit less
shit.
And it is shit, it's barely better than C; it's verbose, nobody knows how
to format 'case' statements, it always seems to violate formatting
standards whenever it's used (disagrees with all code everywhere else),
programmers always seem to disagree on how it should be.
In my opinionated opinion, it always seems to look ugly, and unnecessarily
verbose.

The ugliness of the syntax makes it an unattractive choice for application
to many problems where it may have otherwise been applicable, simplifying
code, and making the code more readable and understandable at a glance.
The switch statement was obviously initially designed to improve clarity;
anything that can be done with a switch statement can easily be done with a
series of if's (if you love squinting at comparative conditions and
constant repetition of the terms being compared), and it probably did
improve clarity, in 1970's...
But I think we could do much better, and offer an interesting and useful
construct that could be used to clarify code in far more locations than it
ever sees use today.


 1.
>> case fall-through is not supported; explicit 'goto case n;' is required. With this in mind, 'break' is unnecessary. Why is it required? It could
>>
>> be implicit upon reaching the next case label, or a scope could be used (with support for omitting the scope for single statements as with if). It's really noisy, and annoying to write everywhere.
>>
>
> Implicit fall-through has been specifically eliminated from the language at my behest. I think it is a fine language change. Use "goto case;" to clarify to the maintainer (and incidentally the compiler) you want a fall-through.


It's a patch on a broken design. If switch used proper scoping rules like everything else, nobody would have ever thought that was a reasonable idea.

To be clear, perhaps I didn't explain myself clearly; I'm not arguing with
the decision about fall-through. I agree that fall-through should be an
explicit request.
I'm suggesting that in the context of D, where fallthrough is not supported
(I offer you congratulations for getting that one in), then 'break;' is
entirely pointless, and shouldn't be required.

I understand the counter argument to be that "if I paste C code into my D
code, there's a potential fail!".
And my response is, I think it's lame to gimp D because a language designed
45 years ago had a crappy design.
The solution is probably to leave switch as is, and introduce a replacement
that's better.

 2.
>> 'case 1, 3, 7, 8:' is awesome! ...but ranged cases have a totally different syntax: 'case 1: .. case 3:'
>>
>> Why settle on that syntax? The inconsistency looks kinda silly when they
>> appear together in code.
>> Surely it's possible to find a syntax that works without repeating case
>> and ':'?
>>
>
> There's no inconsistency. The case is not identical with "foreach (a .. b)" or arr[a .. b], both of which don't include b in the explored range. The fact that "case b:" is present is very telling "b" will be acted upon.


I never suggested a..b used in a switch should be inclusive. I was just
commenting on the choice to use '..' at all.
I have said elsewhere that I agree '..' should indeed be exclusive, just
like everywhere else.
I think the existing syntax is useful for enums, and could remain. Perhaps
both should be supported?


 It's also weird, because it seems that 'case n: .. case m:' is inclusive
>> of m. This may be unexpected.
>>
>
> It's expected.


How so? It seems logical in the context of case statements, but '..' does something different in every other instance. If I were new to D, and I saw that, I imagine it would be perfectly reasonable for me to be confused.


 I'm not sure it's reasonable to use the '..' syntax in this case for
>> that reason. '..' is an [) range, case ranges must be [] so that it makes sense when dealing with enum key ranges.
>>
>
> No.


No what?


 3.
>> Why is 'default' necessary? If I'm not switching on an enumerated type, then many values are meaningless. requiring an empty 'default: break;' line at the end is annoying and noisy.
>>
>
> Explicit is better than implicit.


No.


 I often find myself tempted to rewrite blocks of successive if() logic
>> comparing integers against values/ranges, but it looks silly since the scope rules are not explicit, and 'default: break;' always wastes an extra line.
>>
>
> Write the line.
>

No, it looks stupid. If there are few enough cases, I'll use if's instead
every time.
I lose, and the language loses too.


 I like to reduce noise in my code, and these switch semantics threaten
>> to simplify a lot of code, if not for these strange decisions (purely
>> for legacy compliance?).
>>
>
> I think the current switch statement design is a fine design all things considered (compatibility, law of least surprise, usability, readability).


Well, I disagree. It offers some improvement over the catastrophic design that C gave us almost half a century ago, but it doesn't address the basic un-structured nature of the statement, and deliberately retains all the elements that made it rubbish back when (for compatibility).

Compatibility and law of least surprise I'll grant you.
Usability and readability, I don't think so. Certainly not compared to
competition.

I think what's clear though, is in order to not violate the first 2 (which I agree there is merit in maintaining), any improvement to switch would probably need to come in the form of a new structure, like 'match' in rust, or something designed from the ground-up to not suck, 'select' maybe.

I concede that switch can't be fixed. Perhaps it should be deprecated
instead.
So I guess on that note, I'll leave it there, but I still think it's worth
consideration.
The functionality that switch offers is tremendously useful, and it would
be so much more useful if it were cleaned up; people would actually use it,
and probably in a whole bunch of new applications.
I think you'd see a quick erosion of if/else if sequences if switch was
more awesome.


 Let's consider an example:
>>
>> Code like this:
>>
>> int difficulty = -1;
>> if(e.note.note >= 60 && e.note.note < 72)
>> difficulty = 0;
>> else if(e.note.note >= 72 && e.note.note < 84)
>> difficulty = 1;
>> else if(e.note.note >= 84 && e.note.note < 96)
>> difficulty = 2;
>> else if(e.note.note >= 96 && e.note.note < 108)
>> difficulty = 3;
>>
>> The repetition of e.note.note is annoying, and particular choice of comparisons are liable to result in out-by-ones. It's not nice code to read.
>>
>
> For every proposed tweak there will be an example that makes it look great.
>

I see lots and lots of these; opportunities for a structure like an advanced switch to make really nice.


 Rewrites like this:
>>
>> int difficulty;
>> switch(e.note.note)
>> {
>> case 60: .. case 71:
>> difficulty = 0;
>> break;
>> case 72: .. case 83:
>> difficulty = 1;
>> break;
>> case 84: .. case 95:
>> difficulty = 2;
>> break;
>> case 96: .. case 107:
>> difficulty = 3;
>> break;
>> default:
>> difficulty = -1;
>> break;
>> }
>>
>> That's horrid, it's much longer! And there are pointless wasted lines
>> everywhere.
>> The default case is a total waste, since -1 should just be assigned when
>> initialising the variable above.
>>
>
> But you'd be wasting an extra assignment. I recall you're one for efficiency.
>

I've never encountered an optimiser that would fail on something so simple. Even on my Amiga.


 We can compact it a bit like this:
>>
>> int difficulty;
>> switch(e.note.note)
>> {
>> case 60: .. case 71:
>> difficulty = 0; break;
>> case 72: .. case 83:
>> difficulty = 1; break;
>> case 84: .. case 95:
>> difficulty = 2; break;
>> case 96: .. case 107:
>> difficulty = 3; break;
>> default:
>> difficulty = -1; break;
>> }
>>
>> But that's horrible too.
>>
>
> The quality of being horrible is in the eye of the beholder. I find this code entirely reasonable.


Really?
Can you point me to the paragraph in the formatting/style guide that talks
about appropriate styling for writing multiple statements on the same line?
What happened to DRY?


 It's not clear what vertical offset the 'break'
>> statements shoudl appear at (I hate stacking up multiple statements
>> across the same line!).
>> The the default case is still a waste.
>>
>
> Just do it.


Nope, I'll use if instead.
DRY and all that. I'd rather repeat the term being used for comparison than
repeat 'case' and 'break' all over the place.
'if' produces a similar amount of repetition (perhaps less), but results in
properly scoped statements, and I know how it should be formatted.


 Ideally:
>>
>> int difficulty = -1;
>> switch(e.note.note)
>> {
>> case 60 .. 72:
>> difficulty = 0;
>> case 72 .. 84:
>> difficulty = 1;
>> case 84 .. 96:
>> difficulty = 2;
>> case 96 .. 108:
>> difficulty = 3;
>> }
>>
>
> Nope.


Elaborate?


 'break's are unnecessary since fallthrough isn't allowed.
>>
>
> Silently change the semantics of C code is not something we entertain doing.


I agree, we'd need to distinguish the fixed version.


 Proper numeric range could be supported (assuming [) intervals).
>> 'default' case is unnecessary, and removed.
>>
>> The switch and braces results in 3 extra lines, but I still feel this level of simplification results in code that is MUCH more readable than the sequence of if's I started with. It's super obvious what's going on.
>>
>> I have quite many blocks like this.
>>
>> A great man once (actually, frequently) said "If it doesn't look right,
>> it probably isn't".
>>
>
> The thing is you can apply that to everything, and justify every tweak, because what looks right is subjective.


Are you saying that switch looks pleasing and coherent to you? As compared
with all the other flow control statements existing in D, and competitive
statements from other languages?
Should I start a poll? Perhaps science can tell us if people find it to be
regular and pleasant syntactically.


Finally, you didn't address the suggestion to allow assignment of the switch condition to a properly scoped variable: switch([x =] expression) ? Some expression results don't have an easily named concept. Performing the expression on a prior line and assigning to a temp often results in some pretty stupid variable names polluting the outer scope. And it's annoying.


February 17, 2014
On 2/16/14, 5:03 PM, Walter Bright wrote:
> On 2/16/2014 7:42 AM, Manu wrote:
>> 3. Why is 'default' necessary? If I'm not switching on an enumerated
>> type, then
>> many values are meaningless. requiring an empty 'default: break;' line
>> at the
>> end is annoying and noisy.
>
> It originally was not required, but there was a campaign by a lot of D
> users to make it required to deal with the common bug of adding a value
> in one switch statement but forgetting to add it to another
> corresponding one.

Could you show an example of such scenario? I don't get it.
February 17, 2014
On 17 February 2014 18:43, Walter Bright <newshound2@digitalmars.com> wrote:

> On 2/16/2014 7:39 PM, Manu wrote:
>
>> I think a really useful construct could be made out of switch, but it
>> seems that
>> it won't happen because it must support C code unchanged.
>>
>
> I tend to agree with Andrei on this - the proposals aren't fundamental or game changing, and are kinda just bouncing the rubble around (po-tay-to vs po-tah-to).


Refer to my other reply wrt the 'rubble' concept.

I think a quality implementation would be fairly game changing. A properly
scoped and fully featured switch/select/match statement would result in
some radical simplifications of code all over the place.
Sequential if/if else statements might see a decline, and there would be
far less repetition of terms in the conditional statements.
If switch (or something like it) were massaged to be as nice to use as
foreach is, I think you'll find it will be used all over the place.

Note: I probably wouldn't be exaggerating if I said foreach is the main
reason I started looking into D in the first place. When I first glanced
over the D feature list, I could have easily closed the browser tab, but
that's the thing that kept me reading...
I've said it before, and I'll say it again, I think these things are _so
fundamental_, that their importance is often underestimated, and often
overlooked.
Could you imagine D without foreach? In retrospect, you can't. But If you
were arguing from a position where you never had anything like foreach to
the value of it's inclusion, it wouldn't look anywhere near as strong as it
does in retrospect.

The idea of eliminating many unsightly if/else if blocks is very appealing
to me.
Just scanning through my code, I can imagine so many instances where my
code would become more readable.
People usually use switch today for the same reason, but it's always a hard
call... is the crappiness of 'switch' a quantifiable improvement over the
if/else if sequence? I find myself asking that question all the time.
That's why I brought it up.


> Isn't that the entire point of final switch?
> > Why introduce final switch to address that, then do this aswell?
>
> Implicit in your questions is switches will only be used on enums, i.e. all the values a type can be are known to the compiler. This is only true for a smallish subset of types that are switched on.
>
> final switch : for enums
>
> default : for everything else
>

But... that's like making it an error for an if() to appear without an else
statement. It's _exactly_ like that.
I don't think I couldn't disagree more.

Imagine:

if(condition)
{
  doSomething();
}
else
{}

blah blah.

if(failed)
{
  handleError();
}
else
{}


February 17, 2014
On 17 February 2014 22:38, Chris Cain <clcain@uncg.edu> wrote:

> On Monday, 17 February 2014 at 04:00:08 UTC, Manu wrote:
>
>> Of course, I'd just write the above as:
>>
>>>
>>> int difficulty = e.note.note.between(60,108) ? (e.note.note-60)/12 : -1;
>>>
>>>
>> Yes yes, very clever. Obviously it's an example and could come in any
>> shape
>> or form.
>> Personally, I also wouldn't do that anyway; basic readability has
>> definitely been lost.
>>
>
>
> I know I'm weird here, but I disagree. I had no idea what you were doing at the beginning of the topic, but that one line revealed to me that this is likely related to the music game thing you proposed awhile ago. I can't really explain why "note" was insufficient before to reveal that, but once I saw "12" explicitly on its own I immediately thought ~"12 ... semitones ... octaves ... note ... it's music ... he was working on a music game ... he came up with this while working on the music game".
>
> So, it's classifying difficulty based on which octave a note is for your music game?
>

I'm dealing with arbitrary values as appearing in midi files.
There is a relationship that you made, kind of... but it's incidental. It's
actually an abuse of the structure of a midi file to relate concepts to
octaves; designers use the separation of octaves in midi composition
software to separate some arbitrary data, because octaves often provide
good visual separation in editors, making it easier to visualise the data
they're authoring.
It's also just the one that was on my screen when I cut and pasted. There
are lots of others that lead me to consider this as a frequently recurring
pattern and become annoyed that my code was was uniformly ugly.


Of course, I might be wrong here. It just seems to me that the reducing of
> information made it clearer what the purpose is disregarding the other contextual information that probably exists outside of what you're trying to show us.
>

The purpose is kinda unrelated conceptually. In reality, what has happened
is that you have become confused.
You were searching for reason where there is none, and the algorithmic
expression lead you to a false conclusion :)


February 17, 2014
2014-02-17 22:33 GMT+09:00 Manu <turkeyman@gmail.com>:

> On 17 February 2014 16:18, Andrei Alexandrescu < SeeWebsiteForEmail@erdani.org> wrote:
>
>> On 2/16/14, 7:42 AM, Manu wrote:
>>
>>> So D offers great improvements to switch(), but there are a few small
>>> things I wonder about.
>>>
>>
>> TL;DR of my answer to this: at some point we must get used to the notion that minute syntax tweaks are always possible that make us feel we're making progress when instead we're just moving the rubble around.
>>
>
> OT: Do you realise how harsh your posts often appear to people? I often find I need to restrain myself when replying to your blunt dismissals of peoples opinions/suggestions.
>
> So, you admit that this is a disaster site, but are reluctant to consider
> what good may come of it?
> I'm not suggesting to move the rubble around a bit, I'm suggesting a
> missed opportunity to build something new and useful from the rubble.
>

I completely agree with Andrei. We should continue to keep that D is the successor of the most used system languages - C and C++. it's a *huge* advantage against other modern languages.

Kenji Hara


February 17, 2014
On 18 February 2014 01:02, Kenji Hara <k.hara.pg@gmail.com> wrote:

> 2014-02-17 22:33 GMT+09:00 Manu <turkeyman@gmail.com>:
>
> On 17 February 2014 16:18, Andrei Alexandrescu <
>> SeeWebsiteForEmail@erdani.org> wrote:
>>
>>> On 2/16/14, 7:42 AM, Manu wrote:
>>>
>>>> So D offers great improvements to switch(), but there are a few small
>>>> things I wonder about.
>>>>
>>>
>>> TL;DR of my answer to this: at some point we must get used to the notion that minute syntax tweaks are always possible that make us feel we're making progress when instead we're just moving the rubble around.
>>>
>>
>> OT: Do you realise how harsh your posts often appear to people? I often find I need to restrain myself when replying to your blunt dismissals of peoples opinions/suggestions.
>>
>> So, you admit that this is a disaster site, but are reluctant to consider
>> what good may come of it?
>> I'm not suggesting to move the rubble around a bit, I'm suggesting a
>> missed opportunity to build something new and useful from the rubble.
>>
>
> I completely agree with Andrei. We should continue to keep that D is the successor of the most used system languages - C and C++. it's a *huge* advantage against other modern languages.
>

I agree, to an extent. That's why I say if it is to be improved, I guess it
needs a new name.
foreach eliminated almost all instances of for. I don't think anyone's
upset about that.


February 17, 2014
"Manu" <turkeyman@gmail.com> wrote in message news:mailman.156.1392649746.6445.digitalmars-d@puremagic.com...

> I agree, to an extent. That's why I say if it is to be improved, I guess it needs a new
> name.
> foreach eliminated almost all instances of for. I don't think anyone's upset about
> that.

Exactly, foreach is a new, better language construct, but we didn't butcher for.  I would love to see a nice solid proposal for 'match'. 

February 17, 2014
On 2/17/14, 7:42 AM, Daniel Murphy wrote:
>
> "Manu" <turkeyman@gmail.com> wrote in message
> news:mailman.156.1392649746.6445.digitalmars-d@puremagic.com...
>
>> I agree, to an extent. That's why I say if it is to be improved, I
>> guess it needs a new
>> name.
>> foreach eliminated almost all instances of for. I don't think anyone's
>> upset about
>> that.
>
> Exactly, foreach is a new, better language construct, but we didn't
> butcher for.  I would love to see a nice solid proposal for 'match'.

A "match" statement that figures type patterns and introduce names and all that - that might be more interesting (though being far from a game changer). But that's not quite what has been proposed in this thread.

Andrei