www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Improvement to switch-case statement

reply Mike James <foo bar.com> writes:
Just an idea that could improve Ds switch-case statement - add an elipsys as in
object Pascal to allow case ranges.

switch (var) {
    case 1:
        \\ do something
        break;
    case 2..10:
        \\ do something else
        break;
}

What do people think?

-=mike=-
Dec 31 2008
next sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Wed, Dec 31, 2008 at 5:16 PM, Mike James <foo bar.com> wrote:
 Just an idea that could improve Ds switch-case statement - add an elipsys as
in object Pascal to allow case ranges.

 switch (var) {
    case 1:
        \\ do something
        break;
    case 2..10:
        \\ do something else
        break;
 }

 What do people think?

It's such a common need, and such a simple thing to implement, that I'm absolutely shocked that more languages _haven't_ adopted it. It's annoying when you're writing some kind of string parser and have to put all sorts of stuff in the 'default' that could easily be handled by cases like this. In fact, I'll put it in MiniD right now. Geez.
Dec 31 2008
prev sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Mike James wrote:
 Just an idea that could improve Ds switch-case statement - add an elipsys as
in object Pascal to allow case ranges.

 switch (var) {
      case 1:
          \\ do something
          break;
      case 2..10:
          \\ do something else
          break;
 }

 What do people think?

 -=mike=-

vote-- IMO, either the switch statement should remain the low level (effiecient) construct as in C, or replaced by a general mechanism of pattern matching. your solution is kinda between the two above options and I don't see the point of it. I'd personally prefer pattern matching to be added to D and the switch to be deprecated and eventually removed from the language.
Dec 31 2008
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thu, Jan 01, 2009 at 12:45:39AM +0200, Yigal Chripun wrote:
 IMO, either the switch statement should remain the low level 
 (effiecient) construct as in C, or replaced by a general mechanism of 
 pattern matching. 

This wouldn't be any less efficient than any other switch statement; writing case 2..5: code; break; could just be magically converted into case 2: case 3: case 4: case 5: code; break; That's not ideal when doing a huge range; I'd probably write it like so in asm: cmp ax, 2 je code cmp ax, 3 je code cmp ax, 4 je code cmp ax, 5 je code ; more cases.... jmp default code: ; the code from inside the case goes here Doing a bigger range could let you write something more like this: cmp ax, 2 jl more_cases cmp ax, 5 jg more_cases ; case 2..5 code here more_cases: ; check other cases jmp default Or maybe: cmp ax, 2 jge code more_cases: ; more cases.... jmp default code: cmp ax, 5 jg more_cases ; proceed with the code inside If I was writing it by hand, I'd probably pick one based on what other cases there are to try and minimize the jumps. The compiler could surely do the same. Anyway though, the point is the simple range in the case is at least no worse than writing it in C with a series of cases, and might be better, since the compiler can condense it all down into just a few instructions rather than a big laundry list. Finally, the D switch statement already does strings as cases, which the one in C would never do; the D switch already has moved beyond it, so it wouldn't be out of character for it to pick up the ranges too. -- Adam D. Ruppe http://arsdnet.net
Dec 31 2008
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 case 2..5:
   code;
   break;
 
 could just be magically converted into
 case 2:
 case 3:
 case 4:
 case 5:
   code;
   break;

Note that the following syntax is already possible in D: case 2,3,4,5: code; break; But the range gets larger that syntax gets ugly, so the .. range looks like a good thing to have. So I'm +1 on the idea of the original poster. The range syntax of the D2 foreach may be even extended to support: if (x in 10..20) {... That more or less equals to the C macro: #define InRange(x, a, b) (unsigned((x) - (a)) <= (b) - (a)) That as you can see has just one branch instead of the usual two: http://smallcode.weblogs.us/checking_if_point_belongs_to_interval Bye, bearophile
Dec 31 2008
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2008-12-31 18:22:32 -0500, "Adam D. Ruppe" <destructionator gmail.com> said:

 This wouldn't be any less efficient than any other switch statement; writing
 
 case 2..5:
   code;
   break;
 
 could just be magically converted into
 
 case 2:
 case 3:
 case 4:
 case 5:
   code;
   break;

Except that if you want to keep consistency with array slices, 2..5 should probably not include 5 in the range, thus should be equivalent "case 2,3,4". Unfortunatly, that's generally not what you want when creating such cases. Imagine writting: case 'a'..'{': case 'A'..'[': Concistent, yes; but not very appealing. What you want to be able to write is this: case 'a'..'z': case 'A'..'Z': But then it doesn't work as elsewhere in the language anymore. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 31 2008
next sibling parent reply John Reimer <terminal.node gmail.com> writes:
Hello Michel,

 On 2008-12-31 18:22:32 -0500, "Adam D. Ruppe"
 <destructionator gmail.com> said:
 
 This wouldn't be any less efficient than any other switch statement;
 writing
 
 case 2..5:
 code;
 break;
 could just be magically converted into
 
 case 2:
 case 3:
 case 4:
 case 5:
 code;
 break;

should probably not include 5 in the range, thus should be equivalent "case 2,3,4". Unfortunatly, that's generally not what you want when creating such cases. Imagine writting: case 'a'..'{': case 'A'..'[': Concistent, yes; but not very appealing. What you want to be able to write is this: case 'a'..'z': case 'A'..'Z': But then it doesn't work as elsewhere in the language anymore.

Good point. So while the '..' is potentially useful, it may just be simpler to implement something like a range macro rather than suffer the risk of such an inconsistancy. -JJR
Dec 31 2008
parent John Reimer <terminal.node gmail.com> writes:
Hello John,

 Hello Michel,
 
 On 2008-12-31 18:22:32 -0500, "Adam D. Ruppe"
 <destructionator gmail.com> said:
 This wouldn't be any less efficient than any other switch statement;
 writing
 
 case 2..5:
 code;
 break;
 could just be magically converted into
 case 2:
 case 3:
 case 4:
 case 5:
 code;
 break;

should probably not include 5 in the range, thus should be equivalent "case 2,3,4". Unfortunatly, that's generally not what you want when creating such cases. Imagine writting: case 'a'..'{': case 'A'..'[': Concistent, yes; but not very appealing. What you want to be able to write is this: case 'a'..'z': case 'A'..'Z': But then it doesn't work as elsewhere in the language anymore.

simpler to implement something like a range macro rather than suffer the risk of such an inconsistancy. -JJR

Of course, here it seems we're starting to enter the domain of regular expression parsing anyway, so it leaves one wondering if it's worth fixing up the switch statement too much for this. :) Very likely better to pursue a macro-like epression here. -JJR
Dec 31 2008
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Michel Fortin Wrote:
 Imagine writting:
 
 	case 'a'..'{':
 	case 'A'..'[':
 
 Concistent, yes; but not very appealing. What you want to be able to 
 write is this:
 
 	case 'a'..'z':
 	case 'A'..'Z':
 
 But then it doesn't work as elsewhere in the language anymore.

Ruby solves the problem having two different syntaxed, .. and ... for open and closed intervals. But I don't like it much, it's easy to miss the extra point. An easy solution: case 'a' .. 'z'+1: case 'A' .. 'Z'+1: Bye, bearophile
Dec 31 2008
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Michel Fortin wrote:
 On 2008-12-31 18:22:32 -0500, "Adam D. Ruppe" 
 <destructionator gmail.com> said:
 
 This wouldn't be any less efficient than any other switch statement; 
 writing

 case 2..5:
   code;
   break;

 could just be magically converted into

 case 2:
 case 3:
 case 4:
 case 5:
   code;
   break;

Except that if you want to keep consistency with array slices, 2..5 should probably not include 5 in the range, thus should be equivalent "case 2,3,4". Unfortunatly, that's generally not what you want when creating such cases. Imagine writting: case 'a'..'{': case 'A'..'[': Concistent, yes; but not very appealing. What you want to be able to write is this: case 'a'..'z': case 'A'..'Z': But then it doesn't work as elsewhere in the language anymore.

Python solves this rather elegantly; instead of if( chr in 2..5 ) ... you can just do this: if( 2 <= chr <= 5 ) ... which allows you to explicitly control which ends are inclusive/exclusive. -- Daniel
Dec 31 2008
parent "Nick Sabalausky" <a a.a> writes:
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
news:gjhapq$171v$1 digitalmars.com...
 Michel Fortin wrote:
 On 2008-12-31 18:22:32 -0500, "Adam D. Ruppe" <destructionator gmail.com> 
 said:

 This wouldn't be any less efficient than any other switch statement; 
 writing

 case 2..5:
   code;
   break;

 could just be magically converted into

 case 2:
 case 3:
 case 4:
 case 5:
   code;
   break;

Except that if you want to keep consistency with array slices, 2..5 should probably not include 5 in the range, thus should be equivalent "case 2,3,4". Unfortunatly, that's generally not what you want when creating such cases. Imagine writting: case 'a'..'{': case 'A'..'[': Concistent, yes; but not very appealing. What you want to be able to write is this: case 'a'..'z': case 'A'..'Z': But then it doesn't work as elsewhere in the language anymore.

Python solves this rather elegantly; instead of if( chr in 2..5 ) ... you can just do this: if( 2 <= chr <= 5 ) ... which allows you to explicitly control which ends are inclusive/exclusive.

Not a bad idea. How does it handle something like this: if( a > b < c) Is that an error? Or does it get split into: if( a > b && b < c)
Jan 01 2009
prev sibling next sibling parent reply John Reimer <terminal.node gmail.com> writes:
Hello Yigal,

 Mike James wrote:
 
 Just an idea that could improve Ds switch-case statement - add an
 elipsys as in object Pascal to allow case ranges.
 
 switch (var) {
 case 1:
 \\ do something
 break;
 case 2..10:
 \\ do something else
 break;
 }
 What do people think?
 
 -=mike=-
 

IMO, either the switch statement should remain the low level (effiecient) construct as in C, or replaced by a general mechanism of pattern matching. your solution is kinda between the two above options and I don't see the point of it. I'd personally prefer pattern matching to be added to D and the switch to be deprecated and eventually removed from the language.

Well, the D switch statement has already abandoned the low-level C construct in that it allows for switching on strings. I don't think there is a reason to believe that adding the range feature would mean a loss of efficiency. I have to agree that this would appear to be a fairly simple and useful feature that exists in other "old" languages like Pascal and derivitives. I'm not sure why it was left out in D, but I wouldn't be a bit surprised if the request has been made before. On the other hand, it probably wouldn't be hard to implement a range as a compile time template (or plain) function inserted after the case statement: case range(2,10): // But then again... since array slices make use of "..", it seems a shame that it can't also be used in the case statement for a similar purpose. -JJR
Dec 31 2008
next sibling parent John Reimer <terminal.node gmail.com> writes:
 
 case range(2,10): //
 

Er... pardon... I don't think that would work with CTFI. I was thinking too quickly on that one. :P -JJR
Dec 31 2008
prev sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
John Reimer wrote:
 Hello Yigal,

 Mike James wrote:

 Just an idea that could improve Ds switch-case statement - add an
 elipsys as in object Pascal to allow case ranges.

 switch (var) {
 case 1:
 \\ do something
 break;
 case 2..10:
 \\ do something else
 break;
 }
 What do people think?

 -=mike=-

IMO, either the switch statement should remain the low level (effiecient) construct as in C, or replaced by a general mechanism of pattern matching. your solution is kinda between the two above options and I don't see the point of it. I'd personally prefer pattern matching to be added to D and the switch to be deprecated and eventually removed from the language.

Well, the D switch statement has already abandoned the low-level C construct in that it allows for switching on strings. I don't think there is a reason to believe that adding the range feature would mean a loss of efficiency. I have to agree that this would appear to be a fairly simple and useful feature that exists in other "old" languages like Pascal and derivitives. I'm not sure why it was left out in D, but I wouldn't be a bit surprised if the request has been made before. On the other hand, it probably wouldn't be hard to implement a range as a compile time template (or plain) function inserted after the case statement: case range(2,10): // But then again... since array slices make use of "..", it seems a shame that it can't also be used in the case statement for a similar purpose. -JJR

D's switch is indeed better than C already but it still is rather low-level at least from a syntax point of view: it uses labels and break. Can the current switch be extended to support full pattern matching without conflicting with the current syntax? what about specifying alist of values, like: case 1,2,3:...
Dec 31 2008
parent John Reimer <terminal.node gmail.com> writes:
Hello Yigal,

 John Reimer wrote:
 
 Hello Yigal,
 
 Mike James wrote:
 
 Just an idea that could improve Ds switch-case statement - add an
 elipsys as in object Pascal to allow case ranges.
 
 switch (var) {
 case 1:
 \\ do something
 break;
 case 2..10:
 \\ do something else
 break;
 }
 What do people think?
 -=mike=-
 

IMO, either the switch statement should remain the low level (effiecient) construct as in C, or replaced by a general mechanism of pattern matching. your solution is kinda between the two above options and I don't see the point of it. I'd personally prefer pattern matching to be added to D and the switch to be deprecated and eventually removed from the language.

construct in that it allows for switching on strings. I don't think there is a reason to believe that adding the range feature would mean a loss of efficiency. I have to agree that this would appear to be a fairly simple and useful feature that exists in other "old" languages like Pascal and derivitives. I'm not sure why it was left out in D, but I wouldn't be a bit surprised if the request has been made before. On the other hand, it probably wouldn't be hard to implement a range as a compile time template (or plain) function inserted after the case statement: case range(2,10): // But then again... since array slices make use of "..", it seems a shame that it can't also be used in the case statement for a similar purpose. -JJR

low-level at least from a syntax point of view: it uses labels and break. Can the current switch be extended to support full pattern matching without conflicting with the current syntax? what about specifying alist of values, like: case 1,2,3:...

True, a case statment can take a comma-separated expression list like that, so maybe there is an opportunity for a compile-time template mixin or something afterall. I forgot about the comma op. That's makes things a little more promising. -JJR
Dec 31 2008
prev sibling next sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Thu, Jan 1, 2009 at 12:45 PM, Nick Sabalausky <a a.a> wrote:
 Not a bad idea. How does it handle something like this:

 if( a > b < c)

 Is that an error? Or does it get split into:

 if( a > b && b < c)

From the Python docs: "Formally, if a, b, c, ..., y, z are expressions and opa, opb, ..., opy are comparison operators, then a opa b opb c ...y opy z is equivalent to a opa b and b opb c and ... y opy z, except that each expression is evaluated at most once. Note that a opa b opb c doesn't imply any kind of comparison between a and c, so that, e.g., x < y > z is perfectly legal (though perhaps not pretty). "
Jan 01 2009
prev sibling next sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Yigal Chripun wrote:
<snip>
 IMO, either the switch statement should remain the low level 
 (effiecient) construct as in C, or replaced by a general mechanism of 
 pattern matching. your solution is kinda between the two above options 
 and I don't see the point of it.

What would a "general mechanism of pattern matching" involve, and how would it replace switch? Would it replace if as well?
 I'd personally prefer pattern matching to be added to D and the switch 
 to be deprecated and eventually removed from the language.

I'd personally prefer my proposal from years ago to be taken seriously: http://www.digitalmars.com/d/archives/22722.html ISTM silly to improve switch but at the same time keep it restricted to the same old arcane syntax. Stewart.
Jan 02 2009
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Stewart,

 Yigal Chripun wrote:
 <snip>
 IMO, either the switch statement should remain the low level
 (effiecient) construct as in C, or replaced by a general mechanism of
 pattern matching. your solution is kinda between the two above
 options and I don't see the point of it.
 

would it replace switch? Would it replace if as well?
 I'd personally prefer pattern matching to be added to D and the
 switch to be deprecated and eventually removed from the language.
 

seriously: http://www.digitalmars.com/d/archives/22722.html ISTM silly to improve switch but at the same time keep it restricted to the same old arcane syntax. Stewart.

I for one don't like that proposal for a few reasons: Because it looses fall through and adding it back in with "goto case n;" gets messy in generated code. I use fall through an some of my template code. Because it can lead to hard to understand code. you need to examine all cases to find the code path rather than just find a single case with the given value. Allowing the same case in more than one place could lead to some extremely hard to find bugs where the same case is added more than once in error.
Jan 02 2009
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
BCS wrote:
 Reply to Stewart,

 I'd personally prefer my proposal from years ago to be taken
 seriously: http://www.digitalmars.com/d/archives/22722.html

 ISTM silly to improve switch but at the same time keep it restricted
 to the same old arcane syntax.

 Stewart.

I for one don't like that proposal for a few reasons: Because it looses fall through and adding it back in with "goto case n;" gets messy in generated code. I use fall through an some of my template code.

Please read that proposal properly. You'll see that it supports something more general than fall through. Unless your primary reason for using switch is to implement Duff's device or something like that. Notice also that nowhere did I propose removing the old switch syntax. So if you still want it, it's still there.
 Because it can lead to hard to understand code.

I'm sure you could, if you want, write code that is just as obfuscated with the switch we have.
 you need to examine all 
 cases to find the code path rather than just find a single case with the 
 given value.

No I don't. Once I've found a path that matches, I need only to examine those remaining that aren't preceded by else in order to determine whether there are any more.
 Allowing the same case in more than one place could lead to some 
 extremely hard to find bugs where the same case is added more than once 
 in error.

Only if you carry on thinking in terms of C switch. If you think of it as syntactic sugar for if, then it might be easier. Stewart.
Jan 02 2009
parent BCS <ao pathlink.com> writes:
Reply to Stewart,

 BCS wrote:
 
 Reply to Stewart,
 


 I for one don't like that proposal for a few reasons:
 
 Because it looses fall through and adding it back in with "goto case
 n;" gets messy in generated code. I use fall through an some of my
 template code.
 

something more general than fall through. Unless your primary reason for using switch is to implement Duff's device or something like that.

Duff's device is actualy one of the use cases I'm thinking of. However mor generaly I have use for the ability of C's switch to do a "jump into this block at point n" for some runtime n. This is the central device that dparse uses for backtracking. Another use case I can see right off is yield.
 Notice also that nowhere did I propose removing the old switch syntax.
 So if you still want it, it's still there.
 

Ah. I guess I eroneusly assumed that from this threads context.
 Because it can lead to hard to understand code.
 

with the switch we have.

Any obfuscation the current switch can do, the proposal can do as well, however the proposal can do some that the current form can't. Also, the intended use of the proposal tends to add obfuscation IMHO.
 you need to examine all cases to find the code path rather than just
 find a single case with the given value.
 

examine those remaining that aren't preceded by else in order to determine whether there are any more.

that's still more than one. Also you just pointed out another concern: you need to look at all cases to tell if an else section gets executed. With good tools, not a big problem, OTOH...
 Allowing the same case in more than one place could lead to some
 extremely hard to find bugs where the same case is added more than
 once in error.
 

it as syntactic sugar for if, then it might be easier.

What I'm thinking of it as has no bearing on this. Ending up with a second instance of code for a given value when that is incorrect is a bug. If you are pointing out that it can be used as a sequence of "execute this if the value is in this set" blocks then you may have a point, however in that cases I'd say that proposing this in connection with switch is a bad idea as it is to different from switch, and it would tent to imply a "false friend" ( http://en.wikipedia.org/wiki/False_friend )
Jan 02 2009
prev sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
Stewart Gordon wrote:
 Yigal Chripun wrote:
 <snip>
 IMO, either the switch statement should remain the low level
 (effiecient) construct as in C, or replaced by a general mechanism of
 pattern matching. your solution is kinda between the two above options
 and I don't see the point of it.

What would a "general mechanism of pattern matching" involve, and how would it replace switch? Would it replace if as well?
 I'd personally prefer pattern matching to be added to D and the switch
 to be deprecated and eventually removed from the language.

I'd personally prefer my proposal from years ago to be taken seriously: http://www.digitalmars.com/d/archives/22722.html ISTM silly to improve switch but at the same time keep it restricted to the same old arcane syntax. Stewart.

I have several idea on this, nothing finished though: the only reason for switch in the first place is an optimization in the compiler, besides that, there is no need for it at all and everything can be done with a bunch of if statements. we basically need a way to group several if/case statements together and make them refer the same variable. here's a first attempt: match (value) { case(1) foo(); case(2..4) { foo(); case(3) foo3(); bar(); continue; } case(5) {...} case() {...} // this is the default case } to get the old switch behavior of fall through you use continue. and cases can be nested. I'd say that making cases overlap should be compiler error. the only way it makes sense to me to have overlapping cases is in concurrent code but than the code will need to be marked for that anyway. another related thing, the catch list is also a switch. so instead of the current: try { // put code here } catch (ExceptionA e) { } catch (ExceptionB e) { } catch (ExceptionC e) {} we can extend "case" like this: try { // put code here } catch (e) { case(ExceptionA) handleA(e); case(ExceptionB) handleB(e); case(ExceptionC) handleC(e); case() handleDefault(e); } also, some thought should be spent on getting rid of the ternary op syntax since it interferes with other things that could be added to the language (nullable types, for instance)
Jan 02 2009
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Yigal Chripun:
 also, some thought should be spent on getting rid of the ternary op 
 syntax since it interferes with other things that could be added to the 
 language (nullable types, for instance)

But a ternary operator is sometimes handy: when used judiciously it may help the mind of the person that reads the code to form a "chunk", improving code readability a little. And if you want to modify/remove it you have to remember that D is usually designed to act as C when a C syntax is accepted (even if this leads to some bad things, see the syntax of the "switch" statement or the casting mess). There are many possible alternative syntaxes for the ternary operator. Python in the end has accepted this one: z = 1 if x else y That for example can be used like this: print n, "item" + ("" if a == 1 else "s") Bye, bearophile
Jan 02 2009
parent reply Yigal Chripun <yigal100 gmail.com> writes:
bearophile wrote:
 Yigal Chripun:
 also, some thought should be spent on getting rid of the ternary op
 syntax since it interferes with other things that could be added to the
 language (nullable types, for instance)

But a ternary operator is sometimes handy: when used judiciously it may help the mind of the person that reads the code to form a "chunk", improving code readability a little. And if you want to modify/remove it you have to remember that D is usually designed to act as C when a C syntax is accepted (even if this leads to some bad things, see the syntax of the "switch" statement or the casting mess). There are many possible alternative syntaxes for the ternary operator. Python in the end has accepted this one: z = 1 if x else y That for example can be used like this: print n, "item" + ("" if a == 1 else "s") Bye, bearophile

Sorry, I guess I wasn't clear. I meant to say: remove the *current* syntax of the trenary operator. making "if" an expression is one possible solution to this, as you noted above. Maybe it's just me but all those C-style statements seem so arcane and unnessaccary. real OOP languages do not need control structures to be part of the language - they're part of the class library instead. Here's some Smalltalk examples: (and D-like comparable code) 10 times: [ code ]. // 10.times({ code to be repeated }); map each: [ code ]. // map.each((Type val){ code to be repeated }) (var > 5) ifTrue: [] ifFalse: [] // (var > 5).IfTrueFalse(dgTrue, dgFalse); // reverse the order with a different method of boolean objects var (var > 5) ifFalse: [] ifTrue: [] // use just one of the branches: var (var < 6) ifFalse: [] I guess D is unlikely to adopt the above...
Jan 02 2009
parent reply Benji Smith <dlanguage benjismith.net> writes:
Yigal Chripun wrote:
 Maybe it's just me but all those C-style statements seem so arcane and 
 unnessaccary. real OOP languages do not need control structures to be 
 part of the language - they're part of the class library instead.
 Here's some Smalltalk examples: (and D-like comparable code)

Interesting... Assuming the core language had no control structures, how would library authors implement them? If the language itself lacked IF, ELSE, SWITCH, CASE, DO, WHILE, FOR, and presumably GOTO... how exactly would you go about implementing them in a library? --benji
Jan 02 2009
parent Yigal Chripun <yigal100 gmail.com> writes:
Benji Smith wrote:
 Yigal Chripun wrote:
 Maybe it's just me but all those C-style statements seem so arcane and
 unnessaccary. real OOP languages do not need control structures to be
 part of the language - they're part of the class library instead.
 Here's some Smalltalk examples: (and D-like comparable code)

Interesting... Assuming the core language had no control structures, how would library authors implement them? If the language itself lacked IF, ELSE, SWITCH, CASE, DO, WHILE, FOR, and presumably GOTO... how exactly would you go about implementing them in a library? --benji

Simple. using polymorphism and closures (called blocks in Smalltalk). for example, Here's a simple D implementation for "if", "else": abstract class Boolean { void IfTrue(void delegate() dg); void IfFalse(void delegate() dg); void IF_ELSE(void delegate() dgTrue, void delegate() dgFalse) { IfTrue(dgTrue); IfFalse(dgFalse); } ... } class True : Boolean { void IfTrue(void delegate() dg) { dg(); } void IfFalse(void delegate() dg) { /* nothing to do here */ } } // class False is implemented similarly you use it like this: (a > 4).IF_ELSE(dg1, dg2); if (a > 4) is "true" it'll be of the type True (in Smalltalk everything is an object, btw) therefore the methods of True will be called - IfTrue will evaluate the delegate, and IfFalse will do nothing.
Jan 03 2009
prev sibling next sibling parent reply Benji Smith <dlanguage benjismith.net> writes:
Yigal Chripun wrote:
 also, some thought should be spent on getting rid of the ternary op 
 syntax since it interferes with other things that could be added to the 
 language (nullable types, for instance)

Heresy! The ternary operator is one of my favorite tools. If you want to get rid of it, I think you'd have to make the 'if' statement into an expression (which would open up a whole other can of worms). As I showed earlier, there's no ambiguity between the ternary operator and the nullable type suffix. The ambiguity comes from the case statement. In my opinion, the best way to resolve that ambiguity is to add braces around case statments, like this: switch (x) { case 1 { ... } case 2 { ... } default { ... } } But that might make it impossible to implement Duff's Device (blessing or curse? personally, I don't care). And it might imply the creation of a new scope with each case. Currently, a case statement doesn't introduce its own lexical scope. Anyhoo... Don't mess with the ternary operator!! :) --benji
Jan 02 2009
parent "Nick Sabalausky" <a a.a> writes:
"Benji Smith" <dlanguage benjismith.net> wrote in message 
news:gjmikc$vos$1 digitalmars.com...
 Yigal Chripun wrote:
 also, some thought should be spent on getting rid of the ternary op 
 syntax since it interferes with other things that could be added to the 
 language (nullable types, for instance)

Heresy! The ternary operator is one of my favorite tools. If you want to get rid of it, I think you'd have to make the 'if' statement into an expression (which would open up a whole other can of worms). As I showed earlier, there's no ambiguity between the ternary operator and the nullable type suffix. The ambiguity comes from the case statement. In my opinion, the best way to resolve that ambiguity is to add braces around case statments, like this: switch (x) { case 1 { ... } case 2 { ... } default { ... } } But that might make it impossible to implement Duff's Device (blessing or curse? personally, I don't care). And it might imply the creation of a new scope with each case. Currently, a case statement doesn't introduce its own lexical scope. Anyhoo... Don't mess with the ternary operator!! :) --benji

Right. I use ?: constantly. I can't stand having my code littered with this sort of obfuscated clutter... if(someFlag) a = 0; else a = b; // Also note, the lvalue is non-DRY char[] outStr; if(a == 0) outStr = "(zero)"; else outStr = "(non-zero)"; Stdout.formatln("blah blah blah {}", outStr); ...when I could just do a nice, neat, clear (can tell at a glance what's going on): a = someFlag? 0 : b; Stdout.formatln("blah blah blah {}", a==0? "zero" : "non-zero");
Jan 03 2009
prev sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
 Stewart Gordon wrote:
 Yigal Chripun wrote:
 <snip>
 IMO, either the switch statement should remain the low level
 (effiecient) construct as in C, or replaced by a general mechanism of
 pattern matching. your solution is kinda between the two above options
 and I don't see the point of it.

What would a "general mechanism of pattern matching" involve, and how would it replace switch? Would it replace if as well?
 I'd personally prefer pattern matching to be added to D and the switch
 to be deprecated and eventually removed from the language.

I'd personally prefer my proposal from years ago to be taken seriously: http://www.digitalmars.com/d/archives/22722.html ISTM silly to improve switch but at the same time keep it restricted to the same old arcane syntax. Stewart.

I have several idea on this, nothing finished though: the only reason for switch in the first place is an optimization in the compiler, besides that, there is no need for it at all and everything can be done with a bunch of if statements. we basically need a way to group several if/case statements together and make them refer the same variable. here's a first attempt: match (value) { case(1) foo(); case(2..4) { foo(); case(3) foo3(); bar(); continue; } case(5) {...} case() {...} // this is the default case }

So you make the () required so that the {} can be optional. At least it's consistent with most other control flow statements this way. I'm not sure why you need to use up another keyword for this - switch would work fine. At least, I don't think it would lead to any parsing ambiguity, though it might take quite a bit of lookahead to determine which switch syntax is being used. Would continue jump straight into the next case block that is a sibling of the current one, whatever it may be, or what? And where there are uncased statements at the same block level as cased statements, under what circumstances will they be executed? Moreover, will "default" still be legal in place of "case()"? Stewart.
Jan 03 2009
parent Yigal Chripun <yigal100 gmail.com> writes:
Stewart Gordon wrote:
 Stewart Gordon wrote:
 Yigal Chripun wrote:
 <snip>
 IMO, either the switch statement should remain the low level
 (effiecient) construct as in C, or replaced by a general mechanism of
 pattern matching. your solution is kinda between the two above options
 and I don't see the point of it.

What would a "general mechanism of pattern matching" involve, and how would it replace switch? Would it replace if as well?
 I'd personally prefer pattern matching to be added to D and the switch
 to be deprecated and eventually removed from the language.

I'd personally prefer my proposal from years ago to be taken seriously: http://www.digitalmars.com/d/archives/22722.html ISTM silly to improve switch but at the same time keep it restricted to the same old arcane syntax. Stewart.

I have several idea on this, nothing finished though: the only reason for switch in the first place is an optimization in the compiler, besides that, there is no need for it at all and everything can be done with a bunch of if statements. we basically need a way to group several if/case statements together and make them refer the same variable. here's a first attempt: match (value) { case(1) foo(); case(2..4) { foo(); case(3) foo3(); bar(); continue; } case(5) {...} case() {...} // this is the default case }

So you make the () required so that the {} can be optional. At least it's consistent with most other control flow statements this way. I'm not sure why you need to use up another keyword for this - switch would work fine. At least, I don't think it would lead to any parsing ambiguity, though it might take quite a bit of lookahead to determine which switch syntax is being used. Would continue jump straight into the next case block that is a sibling of the current one, whatever it may be, or what? And where there are uncased statements at the same block level as cased statements, under what circumstances will they be executed? Moreover, will "default" still be legal in place of "case()"? Stewart.

like I said, this is just my first attempt... to answer your questions: 1) new keyword is like you said - to prevent ambiguity, but if the compiler can use "switch" without any parsing dificulties than I'm all for utilizing "switch". 2) requiring () is more consistent with the rest of D - const(..), cast(..), etc... also, this way as you noted, the {} are optional 3) continue should be consistent with loops, so it'll jump to next case in list - like current switch fall-through, (similar to 'continue' to next iteration in loop) and if you nest cases or want to skip a case than you can add a label and continue to that label as well. 4) I'm not sure about 'default' isn't it a waste to make it a keyword just for this? is it used anywhere else in the language? 5) i'm unsure about uncased statements - does it make sense to prohibit those? 6)another thing is adding ability to decompose stuff like in FP, for example: match (arr) { // dynamic array case([a, b]) { use a, b here } // match if array has two elements ... }
Jan 03 2009
prev sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sat, Jan 03, 2009 at 01:36:23AM +0200, Yigal Chripun wrote:
 Maybe it's just me but all those C-style statements seem so arcane and 
 unnessaccary. real OOP languages do not need control structures to be 
 part of the language - they're part of the class library instead.

Don't forget that D isn't a "real OOP language" - it specifically is made to allow several programming styles, and the procedural style is one of them. And I say the language is better for it. -- Adam D. Ruppe http://arsdnet.net
Jan 02 2009
parent John Reimer <terminal.node gmail.com> writes:
Hello Adam,

 On Sat, Jan 03, 2009 at 01:36:23AM +0200, Yigal Chripun wrote:
 
 Maybe it's just me but all those C-style statements seem so arcane
 and unnessaccary. real OOP languages do not need control structures
 to be part of the language - they're part of the class library
 instead.
 

made to allow several programming styles, and the procedural style is one of them. And I say the language is better for it.

Yeah, I was just going to say that Smalltalk is the epitome of a pure OOP language, something D was never meant to be. -JJR
Jan 02 2009