www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - request switch statement with common block

reply "JS" <js.mdnq gmail.com> writes:
switch (cond)
     common: always executed code here
     case A : etc...
     ....
}

instead of

if (cond) { always executed code here  }
switch (cond)
     case A : etc...
     ....
}

which requires modification of the condition twice when necessary
Aug 03 2013
next sibling parent "Andrej Mitrovic" <andrej.mitrovich gmail.com> writes:
On Saturday, 3 August 2013 at 14:38:48 UTC, JS wrote:
 switch (cond)
     common: always executed code here
     case A : etc...
     ....
 }

 instead of

 if (cond) { always executed code here  }
 switch (cond)
     case A : etc...
     ....
 }

 which requires modification of the condition twice when 
 necessary

Can you give a real-world example, I'm not sure what's requested here?
Aug 03 2013
prev sibling next sibling parent "MattCodr" <mattcoder hotmail.com> writes:
On Saturday, 3 August 2013 at 14:38:48 UTC, JS wrote:
 switch (cond)
     common: always executed code here
     case A : etc...
     ....
 }

 instead of

 if (cond) { always executed code here  }
 switch (cond)
     case A : etc...
     ....
 }

 which requires modification of the condition twice when 
 necessary

Why don't you just: switch(cond) { default: // YOUR COMMON HERE case A: ... break; ... }
Aug 03 2013
prev sibling next sibling parent dennis luehring <dl.soluz gmx.net> writes:
Am 03.08.2013 16:38, schrieb JS:
 switch (cond)
       common: always executed code here
       case A : etc...
       ....
 }

 instead of

 if (cond) { always executed code here  }
 switch (cond)
       case A : etc...
       ....
 }

 which requires modification of the condition twice when necessary

switch does get an value not an condition in its scope (the cases are the evaluators) what is the sense of common in this switch example? switch(my_enum) { common: printf("common"); case A: printf("A"); break; case B: printf("B"); break; } why not write it like... printf("common"); switch(my_enum) { case A: printf("A"); break; case B: printf("B"); break; } cases are equal-to-value evaluators - so what is the evaluation of "common"? i don't get it, and speaking about fall-through principle is common always fired on start, on end or what?
Aug 03 2013
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 8/3/13 11:38 AM, JS wrote:
 switch (cond)
      common: always executed code here
      case A : etc...
      ....
 }

 instead of

 if (cond) { always executed code here  }
 switch (cond)
      case A : etc...
      ....
 }

 which requires modification of the condition twice when necessary

Do you mean this? switch(cond) { case A: common_code(); // something case B: common_code(); // something else } (common_code() must not be executed if it doesn't hit any switch case)
Aug 03 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 8/3/13 10:21 AM, JS wrote:
 On Saturday, 3 August 2013 at 16:16:24 UTC, Ary Borenszweig wrote:
 On 8/3/13 11:38 AM, JS wrote:
 switch (cond)
     common: always executed code here
     case A : etc...
     ....
 }

 instead of

 if (cond) { always executed code here  }
 switch (cond)
     case A : etc...
     ....
 }

 which requires modification of the condition twice when necessary

Do you mean this? switch(cond) { case A: common_code(); // something case B: common_code(); // something else } (common_code() must not be executed if it doesn't hit any switch case)

exactly

No because your initial rewrite suggested zero is special. But zero has no special meaning to the switch statement. Consider: switch (cond) { common: ... case 0: ... ... } Andrei
Aug 03 2013
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2013 10:45 AM, w0rp wrote:
 I can see you saving a little bit of typing with this, but it's
 not worth it.

It would be a very unconventional syntactic form, and my experience with such things is it'll see very, very little use.
Aug 03 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2013 12:00 PM, JS wrote:
 What I really don't get it is why people think that just because they won't use
 such a feature then it must be useless to everyone else.

You could provide supporting evidence by examining every use of switch in the dmd, phobos, and druntime source code, and see what percentage of those would benefit from your proposal. Consider, for example, the scope guard statement in D. It is extremely useful - but it is an unusual form (doesn't exist in other languages) and programmers just don't think in those terms. Andrei & I constantly have to work at 'selling' the benefits of it. It still hasn't really caught on.
Aug 03 2013
next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2013 1:06 PM, JS wrote:
 On Saturday, 3 August 2013 at 19:22:53 UTC, Walter Bright wrote:
 On 8/3/2013 12:00 PM, JS wrote:
 What I really don't get it is why people think that just because they won't use
 such a feature then it must be useless to everyone else.

You could provide supporting evidence by examining every use of switch in the dmd, phobos, and druntime source code, and see what percentage of those would benefit from your proposal.

This is illogical. The code wasn't written with such a semantic in mind so it would require me to rewrite the library to see how useful it truly is.

There are two kinds of semantic language improvements: 1. one that is transformative to programming style, i.e. you'd write your program in a fundamentally different way, like OOP. 2. one that is automating an existing pattern, which is finding a recurring pattern in code and providing syntactic sugar for it. The foreach loop is in this category. Your proposal looks to me like (2), in fact, you wrote:
 Since the transformation is rather trivial

which supports that categorization. So, to make automating an existing pattern worthwhile, there ought to be a significant percentage of code exhibiting that existing pattern. For example, bearopile listed: enum mysize(T) = T.sizeof; which does automate a commonly recurring pattern.
 You see how difficult is for me to "sell" it.

Yes, and it should be difficult to sell a new language feature.
 For example, suppose what I am suggesting has zero cost to implement and
 maintain...

 Would you allow it in D?

There's no such thing - and certainly your proposal is not. Any syntactic change requires an ongoing cost in: 1. implementation 2. maintenance 3. testing 4. documentation 5. users have to learn it 6. books and tutorials about D have to discuss it Repeat steps 1..6 for every tool that deals with D source code. Therefore, there needs to be an advantage to it that outweigh all of that. It's a high bar. This is true for every language out there, and if you invent your own language, you'll quickly start applying that criteria as well.
Aug 03 2013
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/03/2013 01:38 PM, bearophile wrote:

 enum mysize(T) = T.sizeof;

That works...
 template Pair(T) = Tuple(T, T);

Instead, the following works (alias and !): alias Pair(T) = Tuple!(T, T); Is my change right? Ali
Aug 04 2013
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/4/2013 11:30 AM, bearophile wrote:
 monarch_dodra:

 Awesome. I'll have to introduce std.traits to this new syntax.

That DIP is not updated to what was actually implemented by Kenji. There is support for both enum and alias. But after a good look at my code base I have not found many places where the new syntax is useful. In my opinion it's handy, but it's not a large win. And I still haven't seen any kind of such statistics done on Phobos before the implementation of this feature pair. People have asked for a more general syntax, useful in more templates, but I have not seen a serious answer that explains why DIP42 is a good idea, while the other more general proposal (of a Self or something to be used in templates to make them more DRY) is is worse.

I haven't collected statistics, but I see a repeated pattern in Phobos that is addressed by DIP42. It is also consistent with the other eponymous template shortcuts that enjoy wide usage.
Aug 04 2013
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/3/2013 12:51 PM, JS wrote:
 On Saturday, 3 August 2013 at 19:10:19 UTC, Andre Artus wrote:
 If the implementation is so obviously trivial why don't you implement a proof
 of concept?


Implying that our time is of lesser value than yours does not help sell your ideas :-)
Aug 03 2013
prev sibling parent dennis luehring <dl.soluz gmx.net> writes:
Am 05.08.2013 08:28, schrieb luminousone:
 or perhaps

 for( int i = 0 ; i < 10 ; i ++ )
 in {
       assert( i == 0 );
 }
 out {
       assert( i == 9 );
 }
 body {
      ... stuff ...
 }

that is just evil code if you got something todo before or on the first item of the list do it before the loop - and for the last behind the for loop if we talk about code-duplication then - use an inner function this type of sub-branching "de-looping" is slow (if performance is relevant) and just not foreach-able, and so not functional-style programming - its called "for loop index micro management for unknown reasons" - but many programmers prefer it very much :)
Aug 05 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Saturday, 3 August 2013 at 16:16:24 UTC, Ary Borenszweig wrote:
 On 8/3/13 11:38 AM, JS wrote:
 switch (cond)
     common: always executed code here
     case A : etc...
     ....
 }

 instead of

 if (cond) { always executed code here  }
 switch (cond)
     case A : etc...
     ....
 }

 which requires modification of the condition twice when 
 necessary

Do you mean this? switch(cond) { case A: common_code(); // something case B: common_code(); // something else } (common_code() must not be executed if it doesn't hit any switch case)

exactly
Aug 03 2013
prev sibling next sibling parent "w0rp" <devw0rp gmail.com> writes:
I can see you saving a little bit of typing with this, but it's
not worth it.
Aug 03 2013
prev sibling next sibling parent "MattCoder" <mattcoder hotmail.com> writes:
On Saturday, 3 August 2013 at 18:04:03 UTC, Walter Bright wrote:
 On 8/3/2013 10:45 AM, w0rp wrote:
 I can see you saving a little bit of typing with this, but it's
 not worth it.

It would be a very unconventional syntactic form, and my experience with such things is it'll see very, very little use.

I would like to use this topic and ask if it would be possible to extend a feature of D language like in this case related by the author. Imagine that a user want to put a trigger when "switch statement" match some option, wouldn't be nice if D could do something like this: switch(x){ onBeforeMatch = callFoo(); case n1: ... case n2: ... } Where onBeforeMatch could be onAfterMatch. Matheus.
Aug 03 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Saturday, 3 August 2013 at 17:45:11 UTC, w0rp wrote:
 I can see you saving a little bit of typing with this, but it's
 not worth it.

Um, it can actually save a lot of type and errors. having two places to change is very error prone. if (cond) { } switch(cond) If the condition is complex and one forgets it is the same condition then only changing one block will cause bugs. It is not a hard feature to have AND it is worth it because it is a near zero complex compiler implementation. So, depending on how you define "not worth it", which I take "I'm too lazy to implement it", you could be correct.
Aug 03 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Saturday, 3 August 2013 at 18:51:24 UTC, MattCoder wrote:
 On Saturday, 3 August 2013 at 18:04:03 UTC, Walter Bright wrote:
 On 8/3/2013 10:45 AM, w0rp wrote:
 I can see you saving a little bit of typing with this, but 
 it's
 not worth it.

It would be a very unconventional syntactic form, and my experience with such things is it'll see very, very little use.

I would like to use this topic and ask if it would be possible to extend a feature of D language like in this case related by the author. Imagine that a user want to put a trigger when "switch statement" match some option, wouldn't be nice if D could do something like this: switch(x){ onBeforeMatch = callFoo(); case n1: ... case n2: ... } Where onBeforeMatch could be onAfterMatch. Matheus.

You can accomplish the exact same and more with my suggestion. switch (x) { common: callFooBefore(); case n1: break; case n2: break; default: break; common: callFooAfter(); } else { } This should be the standard template for switch statements... why we must not progress out of the 80's is beyond me... What I really don't get it is why people think that just because they won't use such a feature then it must be useless to everyone else.
Aug 03 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Saturday, 3 August 2013 at 18:56:47 UTC, JS wrote:
 On Saturday, 3 August 2013 at 17:45:11 UTC, w0rp wrote:
 I can see you saving a little bit of typing with this, but it's
 not worth it.

Um, it can actually save a lot of type and errors. having two places to change is very error prone. if (cond) { } switch(cond) If the condition is complex and one forgets it is the same condition then only changing one block will cause bugs. It is not a hard feature to have AND it is worth it because it is a near zero complex compiler implementation. So, depending on how you define "not worth it", which I take "I'm too lazy to implement it", you could be correct.

If the implementation is so obviously trivial why don't you implement a proof of concept? The compiler is open source after all. People routinely underestimate the ripple effect that adding 'trivial' extensions to a language can have on a language.
Aug 03 2013
prev sibling next sibling parent "Meta" <jared771 gmail.com> writes:
On Saturday, 3 August 2013 at 19:10:19 UTC, Andre Artus wrote:
 If the implementation is so obviously trivial why don't you 
 implement a proof of concept? The compiler is open source after 
 all.

This seems like something that would be fairly simple to implement using a mixin template, so you may not have to go as far as hacking the compiler.
Aug 03 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Saturday, 3 August 2013 at 19:10:19 UTC, Andre Artus wrote:
 On Saturday, 3 August 2013 at 18:56:47 UTC, JS wrote:
 On Saturday, 3 August 2013 at 17:45:11 UTC, w0rp wrote:
 I can see you saving a little bit of typing with this, but 
 it's
 not worth it.

Um, it can actually save a lot of type and errors. having two places to change is very error prone. if (cond) { } switch(cond) If the condition is complex and one forgets it is the same condition then only changing one block will cause bugs. It is not a hard feature to have AND it is worth it because it is a near zero complex compiler implementation. So, depending on how you define "not worth it", which I take "I'm too lazy to implement it", you could be correct.

If the implementation is so obviously trivial why don't you implement a proof of concept? The compiler is open source after all.

because I have better things to do and there is an extreme likelihood it won't be accepted.
 People routinely underestimate the ripple effect that adding 
 'trivial' extensions to a language can have on a language.

Um, and people routinely don't think hard enough about the problem to realize the feature is an orthogonal semantic that has no bearing on anything but what it does. Why do I know this? Because the feature is short hand notation that can be directly implemented the long way. If the long way doesn't have problems, then the short way does not have any problems(except if your implementation is bad, but that's not the fault of the short way). I can write a preprocessor to do the things I need to do. I have done it before. The problem is it is hard to make such features robust without some grammatical context such as an ast.
Aug 03 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Saturday, 3 August 2013 at 19:51:33 UTC, JS wrote:
 ...

I am afraid creating your own language may be your only possibility to get a language that shares your views on "proper" design. Because with each new topic it becomes more and more clear that D is unlikely to fit into that picture. Being useful for someone is _not_ enough to add a feature. It must be useful for a very large amount of cases and/or provide some advantage that can't be achieved in 3x-5x amount of code without it. Anything less than this does not pull its own weight.
Aug 03 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Saturday, 3 August 2013 at 19:22:53 UTC, Walter Bright wrote:
 On 8/3/2013 12:00 PM, JS wrote:
 What I really don't get it is why people think that just 
 because they won't use
 such a feature then it must be useless to everyone else.

You could provide supporting evidence by examining every use of switch in the dmd, phobos, and druntime source code, and see what percentage of those would benefit from your proposal.

This is illogical. The code wasn't written with such a semantic in mind so it would require me to rewrite the library to see how useful it truly is. The semantic should stand on it's own. Either it extends some basic functionality in a good way or it doesn't. i.e., Does it add value? If it does, then it should be implemented assuming the implementation costs and maintenance is not high. In this case the implementation costs and maintenance is near constant(since it is an orthogonal semantic not impacting any other aspect in the compiler but the switch statement itself). In fact, if the D compiler had some ability to easily implement transformations then one could simply rewrite the switch statement into what it represents. Such transformations depend only on the local context(what you are immediately transforming) and simply rewrite the code into other code. e.g., compiler see's switch (cond) { <common>: <common_body1> <body_end_statement>; case <symbol> : <case body> [break or return or fallthrough] ... <default> : <default_body> [break or return or fallthrough] <common>: <common_body2> <body_end_statement>; } else <else_body> AND rewrites it to if (cond) { <common_body1> } switch (cond) { case <symbol> : <case body> [break or return or fallthrough] ... <default> : <default_body> [break or return or fallthrough] } if (cond) { <common_body2> } if (!cond) { <else_body> } The second is already valid D. The first is a "short hand" which is less error prone and less verbose. Since the transformation is rather trivial and, in a sense, "linear", it is very low impact to the maintenance and implementation of the compiler. What it offers? Nothing to those that don't use it... everything to those that do.
 Consider, for example, the scope guard statement in D. It is 
 extremely useful - but it is an unusual form (doesn't exist in 
 other languages) and programmers just don't think in those 
 terms. Andrei & I constantly have to work at 'selling' the 
 benefits of it. It still hasn't really caught on.

And what I'm asking for is similar to scope guards for switch statements. You see how difficult is for me to "sell" it. But you can't design a language for the lowest common denominator. The best language available is the one that can do it all for everyone. With such a language everything else will follow. Having features that no one will use is not necessary bad... at some point chances are someone will want that feature and use it. For example, suppose what I am suggesting has zero cost to implement and maintain... Would you allow it in D? If not, why not? What are the drawbacks to having it? Is it error prone? Completely useless(Obviously not, because at least 2 people would find it useful)? etc...
Aug 03 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Regarding the feature proposed here, I think the extra complexity 
added doesn't pay enough back.


Walter Bright:

 You could provide supporting evidence by examining every use of 
 switch in the dmd, phobos, and druntime source code, and see 
 what percentage of those would benefit from your proposal.

Has someone done that regarding the last feature added to D, I mean the support for this syntax: enum mysize(T) = T.sizeof; template Pair(T) = Tuple(T, T); Bye, bearophile
Aug 03 2013
prev sibling next sibling parent "JS" <js.mdnq gmail.com> writes:
On Saturday, 3 August 2013 at 21:42:00 UTC, Walter Bright wrote:
 On 8/3/2013 12:51 PM, JS wrote:
 On Saturday, 3 August 2013 at 19:10:19 UTC, Andre Artus wrote:
 If the implementation is so obviously trivial why don't you 
 implement a proof
 of concept?


Implying that our time is of lesser value than yours does not help sell your ideas :-)

No, you guys have a vested interest in D and are the owners who make the final say so... All I can do is present an argument and watch it get shot down. The only real solution for me is to develop my own language and compilers... But I neither have the time nor the intelligence to do so(at least to do something worthwhile). But nonetheless, there are certain fundamental properties in language design. I believe that a compilers ONLY goal is to make life easier for the programmer. Hence "short form" is key to this when it does not obfuscate. I think using the criteria that only denies features that are useful to only a few programmers is very short sighted. The reason C++ is better than C is because of it's feature set. Stuff like i++(short form) is ONLY for convenience... yet every uses it! NOT because they used it before it exists(obviously) but because the language supported it and then people were able to see how useful it is(and some things take a long time. Basically "How the hell do you know if something is going to be useful to programmers if the language doesn't support it"? The answer? You don't! But you can get a good idea if what you are asking for is a generalization of something. If X is a generalization of Y and Y is used then chances are X will be used at some point when people are able to grasp what it does. For example, what I am proposing is analogous to class inheritance. You have a standard base class(the current switch statement) and a derived class(my extension of the switch). We can use the derived class anywhere we use the base class(we can use the standard switch statement even if we have the ability to use the extended version). Derivation is always good because it is backwards compatible(conceptually). My switch statement extension is fully backwards compatible with the original. Hence, in no way does it break current usage, so no one can get upset it broke their program. But it makes the language more robust, easier to understand in some cases(but not less in any), and is orthogonal to all other language features(so very little maintenance issues/unintended consequences).
Aug 03 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
 So, depending on how you define "not worth it", which I take 
 "I'm too lazy to implement it", you could be correct.



 YaAA:
 If the implementation is so obviously trivial why don't you 
 implement a proof of concept? The compiler is open source 
 after all.


 JS:
 because I have better things to do and there is an extreme 
 likelihood it won't be accepted.

So, you have better things to do, but other people are lazy if they do not implement something you need but they don't? It's a proof of concept, you offer it to other users (if you build it they will come, or not) who, if they find it as useful as you apparently do will lobby on your behalf.
 YaAA
 People routinely underestimate the ripple effect that adding 
 'trivial' extensions to a language can have on a language.


 JS
 Um, and people routinely don't think hard enough about the 
 problem to realize the feature is an orthogonal semantic that 
 has no bearing on anything but what it does.

It's not true that it has no bearing on anything else.
 JS
 Why do I know this?

 Because the feature is short hand notation that can be directly 
 implemented the long way. If the long way doesn't have 
 problems, then the short way does not have any problems(except 
 if your implementation is bad, but that's not the fault of the 
 short way).

 I can write a preprocessor to do the things I need to do. I 
 have done it before. The problem is it is hard to make such 
 features robust without some grammatical context such as an ast.

You have the source code for the compiler at your disposal. If this is as trivial to implement, and as useful to you, as you claim, then I do not see why you cannot knock something together to showcase the feature. Are you unwilling to do any work to see this feature implemented? If so, how can you impugn the work ethic of someone (by implying that they ate lazy), who has already donated their time and toil to you, if they follow suit? Language design is by necessity a conservative affair; it's easy for a language to die a death-by-a-thousand-features. See if you can find some real-world examples of where this pattern could be useful. At the very least you need to specify the construct in more detail addressing, for example, the following: - Does it only work on "final switch" or any switch? - How are non-integer expressions handled, if at all? - How does it interpret 'default'? - How does it deal with range gaps? - ...
Aug 03 2013
prev sibling next sibling parent "Kagamin" <spam here.lot> writes:
On Saturday, 3 August 2013 at 18:56:47 UTC, JS wrote:
 Um, it can actually save a lot of type and errors.

 having two places to change is very error prone.

 if (cond) { }
 switch(cond)

What is error-prone is evaluation of a complex condition twice assuming it will result in the same value. That's also a common error with C macros. You should save the value in a variable: auto cond = complexCond; if (cond) { } switch(cond)...
Aug 04 2013
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Sunday, 4 August 2013 at 01:57:04 UTC, JS wrote:
 Stuff like i++(short form) is ONLY for convenience... yet every 
 uses it! NOT because they used it before it exists(obviously) 
 but because the language supported it and then people were able 
 to see how useful it is(and some things take a long time.

IIRC post/pre-increment/decrement syntax wasn't introduced in C for peoples convenience, it was there to allow naive compilers to use the then faster increment instructions.
Aug 04 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 3 August 2013 at 20:38:37 UTC, bearophile wrote:
 Regarding the feature proposed here, I think the extra 
 complexity added doesn't pay enough back.


 Walter Bright:

 You could provide supporting evidence by examining every use 
 of switch in the dmd, phobos, and druntime source code, and 
 see what percentage of those would benefit from your proposal.

Has someone done that regarding the last feature added to D, I mean the support for this syntax: enum mysize(T) = T.sizeof; template Pair(T) = Tuple(T, T); Bye, bearophile

You pique my interest. What is this? Looks like template shorthand? I didn't find nything about it in docs. Could you share some links about this?
Aug 04 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Sunday, 4 August 2013 at 15:32:17 UTC, monarch_dodra wrote:
 You pique my interest. What is this? Looks like template 
 shorthand? I didn't find nything about it in docs. Could you 
 share some links about this?

http://wiki.dlang.org/DIP42
Aug 04 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Sunday, 4 August 2013 at 10:14:50 UTC, Kagamin wrote:
 On Saturday, 3 August 2013 at 18:56:47 UTC, JS wrote:
 Um, it can actually save a lot of type and errors.

 having two places to change is very error prone.

 if (cond) { }
 switch(cond)

What is error-prone is evaluation of a complex condition twice assuming it will result in the same value. That's also a common error with C macros. You should save the value in a variable: auto cond = complexCond; if (cond) { } switch(cond)...

There is also a subtle, but in my opinion important, distinction between the expressions accepted by 'if' and 'switch'. With 'if' the expression must evaluate to boolean, whereas with 'switch' the expression evaluates to an integral or {w|d}char[] type. With a 'switch' the condition is completed in the 'case'. Taking an example from int number; string message; switch (number) { default: // valid: ends with 'throw' throw new Exception("unknown number"); case 3: message ~= "three "; break; case 4: message ~= "four "; continue; case 5: message ~= "five "; goto case; case 6: message ~= "six "; break; case 1: case 2: message = "one or two"; }
Aug 04 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Sunday, 4 August 2013 at 15:57:32 UTC, Andre Artus wrote:
 On Sunday, 4 August 2013 at 10:14:50 UTC, Kagamin wrote:
 On Saturday, 3 August 2013 at 18:56:47 UTC, JS wrote:
 Um, it can actually save a lot of type and errors.

 having two places to change is very error prone.

 if (cond) { }
 switch(cond)

What is error-prone is evaluation of a complex condition twice assuming it will result in the same value. That's also a common error with C macros. You should save the value in a variable: auto cond = complexCond; if (cond) { } switch(cond)...

There is also a subtle, but in my opinion important, distinction between the expressions accepted by 'if' and 'switch'. With 'if' the expression must evaluate to boolean, whereas with 'switch' the expression evaluates to an integral or {w|d}char[] type. With a 'switch' the condition is completed in the 'case'.

Oops. I think I hit spacebar twice and the message was posted before I finished it. Taking an example from the D language reference,
 int number;
 string message;
 switch (number)
 {
 	default: // valid: ends with 'throw'
 	throw new Exception("unknown number");
 	case 3:
 		message ~= "three "; break;
 	case 4:
 		message ~= "four "; continue;
 	case 5:
 		message ~= "five "; goto case;
 	case 6:
 		message ~= "six "; break;
 	case 1:
 	case 2:
 		message = "one or two";
  }

With the inclusion of 'default' the condition covers the whole range of 'int'. The programmer may only want the pre and post code to be executed for every other case (1..6). switch (number) { default: // valid: ends with 'throw' throw new Exception("unknown number"); case 3: message ~= "three "; break; case 5: message ~= "five "; goto case; case 6: message ~= "six "; break; case 2: message = "one or two"; } Here the range is interrupted, but covered by 'default'. What does the compiler do here? Sorry I have to go make supper now, but I have a lot more to say on this.
Aug 04 2013
prev sibling next sibling parent "MattCoder" <mattcoder hotmail.com> writes:
On Sunday, 4 August 2013 at 16:16:25 UTC, Andre Artus wrote:
 On Sunday, 4 August 2013 at 15:57:32 UTC, Andre Artus wrote:
 On Sunday, 4 August 2013 at 10:14:50 UTC, Kagamin wrote:
 On Saturday, 3 August 2013 at 18:56:47 UTC, JS wrote:
 Um, it can actually save a lot of type and errors.

 having two places to change is very error prone.

 if (cond) { }
 switch(cond)

What is error-prone is evaluation of a complex condition twice assuming it will result in the same value. That's also a common error with C macros. You should save the value in a variable: auto cond = complexCond; if (cond) { } switch(cond)...

There is also a subtle, but in my opinion important, distinction between the expressions accepted by 'if' and 'switch'. With 'if' the expression must evaluate to boolean, whereas with 'switch' the expression evaluates to an integral or {w|d}char[] type. With a 'switch' the condition is completed in the 'case'.

Oops. I think I hit spacebar twice and the message was posted before I finished it. Taking an example from the D language reference,
 int number;
 string message;
 switch (number)
 {
 	default: // valid: ends with 'throw'
 	throw new Exception("unknown number");
 	case 3:
 		message ~= "three "; break;
 	case 4:
 		message ~= "four "; continue;
 	case 5:
 		message ~= "five "; goto case;
 	case 6:
 		message ~= "six "; break;
 	case 1:
 	case 2:
 		message = "one or two";
 }

With the inclusion of 'default' the condition covers the whole range of 'int'. The programmer may only want the pre and post code to be executed for every other case (1..6).

Like I said, it would be nice if we could extend some D features without change the compiler source, maybe like macros in LISP. The switch statement should have an event handler like: onBeforeMatch or onAfterMatch to handle this. But for what I saw on this thread, this is only possible changing the compiler source. :/ Matheus.
Aug 04 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Ali Çehreli:

 template Pair(T) = Tuple(T, T);

Instead, the following works (alias and !): alias Pair(T) = Tuple!(T, T); Is my change right?

Your change is right, I didn't give enough attention on the code I wrote, sorry :-) Bye, bearophile
Aug 04 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 4 August 2013 at 15:38:01 UTC, Dicebot wrote:
 On Sunday, 4 August 2013 at 15:32:17 UTC, monarch_dodra wrote:
 You pique my interest. What is this? Looks like template 
 shorthand? I didn't find nything about it in docs. Could you 
 share some links about this?

http://wiki.dlang.org/DIP42

Awesome. I'll have to introduce std.traits to this new syntax.
Aug 04 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
monarch_dodra:

 Awesome. I'll have to introduce std.traits to this new syntax.

That DIP is not updated to what was actually implemented by Kenji. There is support for both enum and alias. But after a good look at my code base I have not found many places where the new syntax is useful. In my opinion it's handy, but it's not a large win. And I still haven't seen any kind of such statistics done on Phobos before the implementation of this feature pair. People have asked for a more general syntax, useful in more templates, but I have not seen a serious answer that explains why DIP42 is a good idea, while the other more general proposal (of a Self or something to be used in templates to make them more DRY) is is worse. Bye, bearophile
Aug 04 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
 Andre Artus:
 int number;
 string message;
 switch (number)
 {
 	default: // valid: ends with 'throw'
 		throw new Exception("unknown number");
 	case 3:
 		message ~= "three "; break;
 	case 4:
 		message ~= "four "; continue;
 	case 5:
 		message ~= "five "; goto case;
 	case 6:
 		message ~= "six "; break;
 	case 1:
 	case 2:
 		message = "one or two";
 }

 With the inclusion of 'default' the condition covers the whole 
 range of 'int'. The programmer may only want the pre  and post 
 code to be executed for every other case (1..6).


 MattCoder:
 Like I said, it would be nice if we could extend some D 
 features without change the compiler source, maybe like macros 
 in LISP.

It may not always be the case, but in my experience this often leads to write-only code. I'm pretty new to D, so I'm not quite up to speed with the metaprogramming abilities, but I'm under the impression that this is what mixin's are for.
 MattCoder:
 The switch statement should have an event handler like: 
 onBeforeMatch or onAfterMatch to handle this.

 But for what I saw on this thread, this is only possible 
 changing the compiler source. :/

 Matheus.

In order to produce the most sane (in my opinion) construct the code cannot be rewritten as JS suggested:
 JS:

 if (cond) { <common_body1> }
 switch (cond)
 {
     case <symbol> : <case body> [break or return or fallthrough]
     ...
     <default> : <default_body>  [break or return or fallthrough]
 }
 if (cond) { <common_body2> }
 if (!cond) { <else_body> }

As I mentioned before `switch` takes an expression that evaluates to integral or char[], the condition is completed in the `case`. The condition leading to the 'common' entry and exit code must replicate that of the complete switch statement. This begs the question about how to handle `default`. It would be difficult to correctly reason about the code without additional information. The only suggestion that leads to sane results in all (maybe?) cases is that made by Ary Borenszweig.
 Ary Borenszweig:

 switch(cond) {
   case A:
     common_code();
     // something
   case B:
     common_code();
     // something else
 }

I would think that the common code could be factored into a function taking a void delegate (analogous to C# Action<T> delegate) then passing the case specific code as a lambda. This is something I have done in C#, but not yet in D. In C# you would something like this: private void UseAGoodNameDescribingCommonCode(Action action) { // Entry code action(); // Exit code } switch(expression) { case A: UseAGoodNameDescribingCommonCode(() => { // something }); break; case B: UseAGoodNameDescribingCommonCode(() => { // something }); break; default: // Something else } It's very clear where it's being applied, and where it is not. If the compiler was rewriting the following: switch(expression) { common_entry: // should not be order specific i.e. overloading 'common' // entry code break; common_exit: // exit code break; case A: // something break; case B: // something else break; default: // default something } It could produce something like this: switch(expression) { common_entry: // should not be order specific i.e. overloading 'common' // entry code goto pop_label(); common_exit: // exit code break; case A: // could set var or register used push/pop for clarity of intent push_label(A_prime); goto case common_entry; label A_prime: // something goto case common_exit; // break not needed here; case B: // rinse & repeat label B_prime: // rinse & repeat default: // default something } What to do with default needs to be disambiguated.
Aug 04 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Monday, 5 August 2013 at 04:07:55 UTC, Andre Artus wrote:
 Andre Artus:
 int number;
 string message;
 switch (number)
 {
 	default: // valid: ends with 'throw'
 		throw new Exception("unknown number");
 	case 3:
 		message ~= "three "; break;
 	case 4:
 		message ~= "four "; continue;
 	case 5:
 		message ~= "five "; goto case;
 	case 6:
 		message ~= "six "; break;
 	case 1:
 	case 2:
 		message = "one or two";
 }

 With the inclusion of 'default' the condition covers the 
 whole range of 'int'. The programmer may only want the pre  
 and post code to be executed for every other case (1..6).


 MattCoder:
 Like I said, it would be nice if we could extend some D 
 features without change the compiler source, maybe like macros 
 in LISP.

It may not always be the case, but in my experience this often leads to write-only code. I'm pretty new to D, so I'm not quite up to speed with the metaprogramming abilities, but I'm under the impression that this is what mixin's are for.
 MattCoder:
 The switch statement should have an event handler like: 
 onBeforeMatch or onAfterMatch to handle this.

 But for what I saw on this thread, this is only possible 
 changing the compiler source. :/

 Matheus.

In order to produce the most sane (in my opinion) construct the code cannot be rewritten as JS suggested:
 JS:

 if (cond) { <common_body1> }
 switch (cond)
 {
    case <symbol> : <case body> [break or return or fallthrough]
    ...
    <default> : <default_body>  [break or return or fallthrough]
 }
 if (cond) { <common_body2> }
 if (!cond) { <else_body> }

As I mentioned before `switch` takes an expression that evaluates to integral or char[], the condition is completed in the `case`. The condition leading to the 'common' entry and exit code must replicate that of the complete switch statement. This begs the question about how to handle `default`. It would be difficult to correctly reason about the code without additional information. The only suggestion that leads to sane results in all (maybe?) cases is that made by Ary Borenszweig.
 Ary Borenszweig:

 switch(cond) {
  case A:
    common_code();
    // something
  case B:
    common_code();
    // something else
 }

I would think that the common code could be factored into a function taking a void delegate (analogous to C# Action<T> delegate) then passing the case specific code as a lambda. This is something I have done in C#, but not yet in D. In C# you would something like this: private void UseAGoodNameDescribingCommonCode(Action action) { // Entry code action(); // Exit code } switch(expression) { case A: UseAGoodNameDescribingCommonCode(() => { // something }); break; case B: UseAGoodNameDescribingCommonCode(() => { // something }); break; default: // Something else } It's very clear where it's being applied, and where it is not. If the compiler was rewriting the following: switch(expression) { common_entry: // should not be order specific i.e. overloading 'common' // entry code break; common_exit: // exit code break; case A: // something break; case B: // something else break; default: // default something } It could produce something like this: switch(expression) { common_entry: // should not be order specific i.e. overloading 'common' // entry code goto pop_label(); common_exit: // exit code break; case A: // could set var or register used push/pop for clarity of intent push_label(A_prime); goto case common_entry; label A_prime: // something goto case common_exit; // break not needed here; case B: // rinse & repeat label B_prime: // rinse & repeat default: // default something } What to do with default needs to be disambiguated.

I should point out that 'common_entry' and 'common_exit' are not really cases, but labels as they are not explicitly tied to the input expression.
Aug 04 2013
prev sibling next sibling parent "luminousone" <rd.hunt gmail.com> writes:
perhaps a more generic solution should be looked at, extend 
contracts to work with all scope blocks.

switch(somenumber)
in {
     ... before stuff ...
}
out {
     .... after stuff ...
}
body {
     case 1:
     in {
        ... etc ....
     }
     out {
        ... more etc ...
     }
     body {
        ...
     }
     case 2:
       // and so on
}

or perhaps

for( int i = 0 ; i < 10 ; i ++ )
in {
     assert( i == 0 );
}
out {
     assert( i == 9 );
}
body {
    ... stuff ...
}

if it is desired for a particular contract block to be called in 
release builds perhaps a attribute label to mark it as a runtime 
block or something similar.

foreach( i, k ; somerange )
 runtime in {
  ...
}
body {
}
Aug 04 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote:
 perhaps a more generic solution should be looked at, extend 
 contracts to work with all scope blocks.

 switch(somenumber)
 in {
     ... before stuff ...
 }
 out {
     .... after stuff ...
 }
 body {
     case 1:
     in {
        ... etc ....
     }
     out {
        ... more etc ...
     }
     body {
        ...
     }
     case 2:
       // and so on
 }

 or perhaps

 for( int i = 0 ; i < 10 ; i ++ )
 in {
     assert( i == 0 );
 }
 out {
     assert( i == 9 );
 }
 body {
    ... stuff ...
 }

 if it is desired for a particular contract block to be called 
 in release builds perhaps a attribute label to mark it as a 
 runtime block or something similar.

 foreach( i, k ; somerange )
  runtime in {
  ...
 }
 body {
 }

Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming. The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that. At the bottom of this page you can find a reading list for more info. http://www.digitalmars.com/d/dbc.html Or for a general overview: http://en.wikipedia.org/wiki/Design_by_contract Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check?
Aug 05 2013
prev sibling next sibling parent "MattCodr" <mattcoder hotmail.com> writes:
On Monday, 5 August 2013 at 04:07:55 UTC, Andre Artus wrote:
 Andre Artus:
 int number;
 string message;
 switch (number)
 {
 	default: // valid: ends with 'throw'
 		throw new Exception("unknown number");
 	case 3:
 		message ~= "three "; break;
 	case 4:
 		message ~= "four "; continue;
 	case 5:
 		message ~= "five "; goto case;
 	case 6:
 		message ~= "six "; break;
 	case 1:
 	case 2:
 		message = "one or two";
 }

 With the inclusion of 'default' the condition covers the 
 whole range of 'int'. The programmer may only want the pre  
 and post code to be executed for every other case (1..6).


 MattCoder:
 Like I said, it would be nice if we could extend some D 
 features without change the compiler source, maybe like macros 
 in LISP.

It may not always be the case, but in my experience this often leads to write-only code. I'm pretty new to D, so I'm not quite up to speed with the metaprogramming abilities, but I'm under the impression that this is what mixin's are for.

Well I'm not experienced too, but mixin's for what I know just works in compiler time right? But anyway it would be possible to write my own switch version with mixin? I really would like to see this. Matheus.
Aug 05 2013
prev sibling next sibling parent "QAston" <qaston gmail.com> writes:
On Monday, 5 August 2013 at 09:37:11 UTC, dennis luehring wrote:

 this type of sub-branching "de-looping" is slow (if performance 
 is relevant) and just not foreach-able, and so not 
 functional-style programming - its called "for loop index micro 
 management for unknown reasons" - but many programmers prefer 
 it very much :)

It's caused by lack of inner functions in many languages - people use switch+flags or for loops to be more DRY.
Aug 05 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Monday, 5 August 2013 at 11:32:14 UTC, QAston wrote:
 On Monday, 5 August 2013 at 09:37:11 UTC, dennis luehring wrote:

 this type of sub-branching "de-looping" is slow (if 
 performance is relevant) and just not foreach-able, and so not 
 functional-style programming - its called "for loop index 
 micro management for unknown reasons" - but many programmers 
 prefer it very much :)

It's caused by lack of inner functions in many languages - people use switch+flags or for loops to be more DRY.

I was under the impression that D has nested functions, unless by inner function you mean something else.
Aug 05 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
 Andre Artus:

 It may not always be the case, but in my experience this often 
 leads to write-only code.
 I'm pretty new to D, so I'm not quite up to speed with the 
 metaprogramming abilities, but I'm under the impression that 
 this is what mixin's are for.


 MattCoder:

 Well I'm not experienced too, but mixin's for what I know just 
 works in compiler time right?

 But anyway it would be possible to write my own switch version 
 with mixin? I really would like to see this.

 Matheus.

Yes, it takes any string that's valid D. I see people using it to embed domain specific languages (e.g. PEG via PEGGED) so you should easily be able to write a translator/preprocessor that takes your switch and converts it to D code. mixin(" switch (number) { default: // valid: ends with 'throw' throw new Exception("unknown number"); common_entry: // some common entry code break; common_exit: // some common exit code break; case 3: message ~= "three "; break; case 4: message ~= "four "; continue; case 6: message ~= "six "; break; } "); The preprocessor could rewrite to this string: " switch (number) { case 3: case 4: case 6: // some common entry code break; } switch (number) { default: // valid: ends with 'throw' throw new Exception("unknown number"); case 3: message ~= "three "; break; case 4: message ~= "four "; continue; case 6: message ~= "six "; break; } switch (number) { case 3: case 4: case 6: // some common exit code break; } " **** I do not recommend anyone do this **** The reason I would not recommend this is that it leads to brittle code that is hard to debug and reason about. The reason I use `switch`, and not `if` for the entry and exit code is because these should only fire under the same conditions as the cases in the original switch, otherwise you introduce hard to find bugs in your code. Once again, I do not recommend people doing this: my preference is for code that makes the programmers intent clear and explicit.
Aug 05 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Monday, 5 August 2013 at 09:37:11 UTC, dennis luehring wrote:
 Am 05.08.2013 08:28, schrieb luminousone:
 or perhaps

 for( int i = 0 ; i < 10 ; i ++ )
 in {
      assert( i == 0 );
 }
 out {
      assert( i == 9 );
 }
 body {
     ... stuff ...
 }

that is just evil code if you got something todo before or on the first item of the list do it before the loop - and for the last behind the for loop if we talk about code-duplication then - use an inner function this type of sub-branching "de-looping" is slow (if performance is relevant) and just not foreach-able, and so not functional-style programming - its called "for loop index micro management for unknown reasons" - but many programmers prefer it very much :)

I have been programming since '92 and I must say that I have never seen this before. Maybe I've just been lucky, but this kind of thing would never pass a review anywhere I have worked before. Code is a user interface, if the user's model differs from the system model you will get errors. I.e. Junior von Newhire should be able to correctly reason about any piece of the code from day one. If they cannot do so they will introduce bugs.
Aug 05 2013
prev sibling next sibling parent "ron" <rd.hunt gmail.com> writes:
On Monday, 5 August 2013 at 08:46:54 UTC, Andre Artus wrote:
 On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote:
 perhaps a more generic solution should be looked at, extend 
 contracts to work with all scope blocks.

 switch(somenumber)
 in {
    ... before stuff ...
 }
 out {
    .... after stuff ...
 }
 body {
    case 1:
    in {
       ... etc ....
    }
    out {
       ... more etc ...
    }
    body {
       ...
    }
    case 2:
      // and so on
 }

 or perhaps

 for( int i = 0 ; i < 10 ; i ++ )
 in {
    assert( i == 0 );
 }
 out {
    assert( i == 9 );
 }
 body {
   ... stuff ...
 }

 if it is desired for a particular contract block to be called 
 in release builds perhaps a attribute label to mark it as a 
 runtime block or something similar.

 foreach( i, k ; somerange )
  runtime in {
 ...
 }
 body {
 }

Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming. The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that. At the bottom of this page you can find a reading list for more info. http://www.digitalmars.com/d/dbc.html Or for a general overview: http://en.wikipedia.org/wiki/Design_by_contract Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check?

None taken, =-p. I don't see how this is different from current contract usage, right now they apply to function scopes only. currently I believe you could get a similar effect via using an inner function. void a() { int i = 0; void b() in { assert( i == 0 ); } out { assert( i == 10 ); } body { for( ; i < 10 ; i ++ ) { ... do something ... } } b(); }
Aug 05 2013
prev sibling next sibling parent "Borislav Kosharov" <bosak gmail.com> writes:
On Monday, 5 August 2013 at 19:58:21 UTC, ron wrote:
 On Monday, 5 August 2013 at 08:46:54 UTC, Andre Artus wrote:
 On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote:
 perhaps a more generic solution should be looked at, extend 
 contracts to work with all scope blocks.

 switch(somenumber)
 in {
   ... before stuff ...
 }
 out {
   .... after stuff ...
 }
 body {
   case 1:
   in {
      ... etc ....
   }
   out {
      ... more etc ...
   }
   body {
      ...
   }
   case 2:
     // and so on
 }

 or perhaps

 for( int i = 0 ; i < 10 ; i ++ )
 in {
   assert( i == 0 );
 }
 out {
   assert( i == 9 );
 }
 body {
  ... stuff ...
 }

 if it is desired for a particular contract block to be called 
 in release builds perhaps a attribute label to mark it as a 
 runtime block or something similar.

 foreach( i, k ; somerange )
  runtime in {
 ...
 }
 body {
 }

Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming. The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that. At the bottom of this page you can find a reading list for more info. http://www.digitalmars.com/d/dbc.html Or for a general overview: http://en.wikipedia.org/wiki/Design_by_contract Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check?

None taken, =-p. I don't see how this is different from current contract usage, right now they apply to function scopes only. currently I believe you could get a similar effect via using an inner function. void a() { int i = 0; void b() in { assert( i == 0 ); } out { assert( i == 10 ); } body { for( ; i < 10 ; i ++ ) { ... do something ... } } b(); }

Speaking of contracts, and reading the docs I see: "Pre and Post Contracts The pre contracts specify the preconditions before a statement is executed. The most typical use of this would be in validating the parameters to a function. The post contracts validate the result of the statement. The most typical use of this would be in validating the return value of a function and of any side effects it has..." So are contracts possible outside function declarations? For example just scopes or random places in code.
Aug 05 2013
prev sibling next sibling parent "luminousone" <rd.hunt gmail.com> writes:
On Monday, 5 August 2013 at 20:45:47 UTC, Borislav Kosharov wrote:
 On Monday, 5 August 2013 at 19:58:21 UTC, ron wrote:
 On Monday, 5 August 2013 at 08:46:54 UTC, Andre Artus wrote:
 On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote:
 perhaps a more generic solution should be looked at, extend 
 contracts to work with all scope blocks.

 switch(somenumber)
 in {
  ... before stuff ...
 }
 out {
  .... after stuff ...
 }
 body {
  case 1:
  in {
     ... etc ....
  }
  out {
     ... more etc ...
  }
  body {
     ...
  }
  case 2:
    // and so on
 }

 or perhaps

 for( int i = 0 ; i < 10 ; i ++ )
 in {
  assert( i == 0 );
 }
 out {
  assert( i == 9 );
 }
 body {
 ... stuff ...
 }

 if it is desired for a particular contract block to be 
 called in release builds perhaps a attribute label to mark 
 it as a runtime block or something similar.

 foreach( i, k ; somerange )
  runtime in {
 ...
 }
 body {
 }

Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming. The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that. At the bottom of this page you can find a reading list for more info. http://www.digitalmars.com/d/dbc.html Or for a general overview: http://en.wikipedia.org/wiki/Design_by_contract Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check?

None taken, =-p. I don't see how this is different from current contract usage, right now they apply to function scopes only. currently I believe you could get a similar effect via using an inner function. void a() { int i = 0; void b() in { assert( i == 0 ); } out { assert( i == 10 ); } body { for( ; i < 10 ; i ++ ) { ... do something ... } } b(); }

Speaking of contracts, and reading the docs I see: "Pre and Post Contracts The pre contracts specify the preconditions before a statement is executed. The most typical use of this would be in validating the parameters to a function. The post contracts validate the result of the statement. The most typical use of this would be in validating the return value of a function and of any side effects it has..." So are contracts possible outside function declarations? For example just scopes or random places in code.

I being zero is the precondition for that loop, and i being 10 is the post condition for that loop. Pretty much I think that any scope can potentially fit the definition for contracts. Really any block of code, can be considered to have pre and post conditions, functions just happen to be one way to organize code.
Aug 05 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Monday, 5 August 2013 at 19:58:21 UTC, ron wrote:
 On Monday, 5 August 2013 at 08:46:54 UTC, Andre Artus wrote:
 On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote:
 perhaps a more generic solution should be looked at, extend 
 contracts to work with all scope blocks.

 switch(somenumber)
 in {
   ... before stuff ...
 }
 out {
   .... after stuff ...
 }
 body {
   case 1:
   in {
      ... etc ....
   }
   out {
      ... more etc ...
   }
   body {
      ...
   }
   case 2:
     // and so on
 }

 or perhaps

 for( int i = 0 ; i < 10 ; i ++ )
 in {
   assert( i == 0 );
 }
 out {
   assert( i == 9 );
 }
 body {
  ... stuff ...
 }

 if it is desired for a particular contract block to be called 
 in release builds perhaps a attribute label to mark it as a 
 runtime block or something similar.

 foreach( i, k ; somerange )
  runtime in {
 ...
 }
 body {
 }

Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming. The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that. At the bottom of this page you can find a reading list for more info. http://www.digitalmars.com/d/dbc.html Or for a general overview: http://en.wikipedia.org/wiki/Design_by_contract Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check?

None taken, =-p. I don't see how this is different from current contract usage, right now they apply to function scopes only. currently I believe you could get a similar effect via using an inner function. void a() { int i = 0; void b() in { assert( i == 0 ); } out { assert( i == 10 ); } body { for( ; i < 10 ; i ++ ) { ... do something ... } } b(); }

I could be missing something, if so please clarify. The construct I have issue with is this one,
 switch(somenumber)
 in {
   ... before stuff ...
 }
 out {
   .... after stuff ...
 }



I would contend that code within in/out/invariant blocks should be 'pure' (no state changes, no IO [other than assert throwing]), it's only there to validate that a class and it's methods do not violate certain conditions. They should be able to be stripped out of the release build without altering the execution of the application in any way. A classic example is the null dereference check, which some compilers and most (all?) static analysers can detect. string whoIsAMonkey(Person p) in { assert(p !is null, "Person can not be null"); assert(!isNullOrEmpty(p.Name), "Person name can not be null or empty"); } body { return p.Name ~ " is a monkey!"; } void main() { Person p = null; // Compiler / analyser should complain with // "Person can not be null" writeln(whoIsAMonkey(p)); // ^ here } void main() { Person p = new Person(); // Compiler / analyser should complain with // "Person name can not be null or empty" writeln(whoIsAMonkey(p)); } etc. Contracts are meant to define the public (*) interface of a class. * By public I mean here anything not 'private', e.g. 'protected' for inheritance. As Andrei points out in his book ("The D Programming Language") contracts are not used to validate/scrub user (or any external) input as they can be compiled out of the executable. Contracts are there to check sanity at compile time, or at the very least during testing. The contract is (or should be) part of the documentation.
Aug 05 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
 Borislav Kosharov wrote:

 Speaking of contracts, and reading the docs I see:
 "Pre and Post Contracts

 The pre contracts specify the preconditions before a statement 
 is executed. The most typical use of this would be in 
 validating the parameters to a function. The post contracts 
 validate the result of the statement. The most typical use of 
 this would be in validating the return value of a function and 
 of any side effects it has..."

 So are contracts possible outside function declarations? For 
 example just scopes or random places in code.

They should not be. Other than the 'invariant' which is on the class/interface.
Aug 05 2013
prev sibling next sibling parent "luminousone" <rd.hunt gmail.com> writes:
On Monday, 5 August 2013 at 21:48:46 UTC, Andre Artus wrote:
 On Monday, 5 August 2013 at 19:58:21 UTC, ron wrote:
 On Monday, 5 August 2013 at 08:46:54 UTC, Andre Artus wrote:
 On Monday, 5 August 2013 at 06:28:12 UTC, luminousone wrote:
 perhaps a more generic solution should be looked at, extend 
 contracts to work with all scope blocks.

 switch(somenumber)
 in {
  ... before stuff ...
 }
 out {
  .... after stuff ...
 }
 body {
  case 1:
  in {
     ... etc ....
  }
  out {
     ... more etc ...
  }
  body {
     ...
  }
  case 2:
    // and so on
 }

 or perhaps

 for( int i = 0 ; i < 10 ; i ++ )
 in {
  assert( i == 0 );
 }
 out {
  assert( i == 9 );
 }
 body {
 ... stuff ...
 }

 if it is desired for a particular contract block to be 
 called in release builds perhaps a attribute label to mark 
 it as a runtime block or something similar.

 foreach( i, k ; somerange )
  runtime in {
 ...
 }
 body {
 }

Please do not take offense, but I do not see this as a good idea. Contracts have a very different function; not just in D, but every language that uses them. The idea is to support design-by-contract programming. Overloading the constructs for the purposes proposed here would, in my opinion, cause confusion and/or weaken the proper use of contract programming. The code in the contract conditions should never do anything more than what is necessary to specify the contract. It should not do explicit IO (other than implied by assert()), mutate state, or anything like that. At the bottom of this page you can find a reading list for more info. http://www.digitalmars.com/d/dbc.html Or for a general overview: http://en.wikipedia.org/wiki/Design_by_contract Walter, does the D compiler or any of it's companion tools do any static analysis on the contracts? Such as a void safety/null reference check?

None taken, =-p. I don't see how this is different from current contract usage, right now they apply to function scopes only. currently I believe you could get a similar effect via using an inner function. void a() { int i = 0; void b() in { assert( i == 0 ); } out { assert( i == 10 ); } body { for( ; i < 10 ; i ++ ) { ... do something ... } } b(); }

I could be missing something, if so please clarify. The construct I have issue with is this one,
 switch(somenumber)
 in {
  ... before stuff ...
 }
 out {
  .... after stuff ...
 }



I would contend that code within in/out/invariant blocks should be 'pure' (no state changes, no IO [other than assert throwing]), it's only there to validate that a class and it's methods do not violate certain conditions. They should be able to be stripped out of the release build without altering the execution of the application in any way. A classic example is the null dereference check, which some compilers and most (all?) static analysers can detect. string whoIsAMonkey(Person p) in { assert(p !is null, "Person can not be null"); assert(!isNullOrEmpty(p.Name), "Person name can not be null or empty"); } body { return p.Name ~ " is a monkey!"; } void main() { Person p = null; // Compiler / analyser should complain with // "Person can not be null" writeln(whoIsAMonkey(p)); // ^ here } void main() { Person p = new Person(); // Compiler / analyser should complain with // "Person name can not be null or empty" writeln(whoIsAMonkey(p)); } etc. Contracts are meant to define the public (*) interface of a class. * By public I mean here anything not 'private', e.g. 'protected' for inheritance. As Andrei points out in his book ("The D Programming Language") contracts are not used to validate/scrub user (or any external) input as they can be compiled out of the executable. Contracts are there to check sanity at compile time, or at the very least during testing. The contract is (or should be) part of the documentation.

You are correct. I will have to check out his book.
Aug 05 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
 As Andrei points out in his book ("The D Programming 
 Language") contracts are not used to validate/scrub user (or 
 any external) input as they can be compiled out of the 
 executable.

 Contracts are there to check sanity at compile time, or at the 
 very least during testing.

 The contract is (or should be) part of the documentation.

You are correct. I will have to check out his book.

Be sure to check out the errata page http://erdani.com/tdpl/errata/
Aug 05 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Saturday, 3 August 2013 at 19:22:53 UTC, Walter Bright wrote:
 On 8/3/2013 12:00 PM, JS wrote:
 What I really don't get it is why people think that just 
 because they won't use
 such a feature then it must be useless to everyone else.

You could provide supporting evidence by examining every use of switch in the dmd, phobos, and druntime source code, and see what percentage of those would benefit from your proposal. Consider, for example, the scope guard statement in D. It is extremely useful - but it is an unusual form (doesn't exist in other languages) and programmers just don't think in those terms. Andrei & I constantly have to work at 'selling' the benefits of it. It still hasn't really caught on.

The scope guard statement is my all-time favourite feature in D. It's so much easier to reason about than several layers of try/catch/finally. A close second is the Contracts, especially as it can be applied to interfaces. a huge win for service oriented programming.
Aug 05 2013
prev sibling next sibling parent "QAston" <qaston gmail.com> writes:
 I was under the impression that D has nested functions, unless 
 by inner function you mean something else.

Yeah, pardon my terminology.
Aug 06 2013
prev sibling next sibling parent "Andre Artus" <andre.artus gmail.com> writes:
On Tuesday, 6 August 2013 at 07:44:46 UTC, QAston wrote:
 I was under the impression that D has nested functions, unless 
 by inner function you mean something else.

Yeah, pardon my terminology.

Not an issue, they normally mean the same thing. I believe JS's use case can be covered easily and clearly using a nested function taking a void delegate. With the not insubstatial benefit of being easier to debug.
Aug 06 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Aug 03, 2013 at 12:22:53PM -0700, Walter Bright wrote:
 On 8/3/2013 12:00 PM, JS wrote:
What I really don't get it is why people think that just because they
won't use such a feature then it must be useless to everyone else.

You could provide supporting evidence by examining every use of switch in the dmd, phobos, and druntime source code, and see what percentage of those would benefit from your proposal. Consider, for example, the scope guard statement in D. It is extremely useful - but it is an unusual form (doesn't exist in other languages) and programmers just don't think in those terms. Andrei & I constantly have to work at 'selling' the benefits of it. It still hasn't really caught on.

At least it has caught on with me. :) After learning about scope guards in D, I've been plagued with persistent thoughts of "I wish I could use a scope guard here!" every time I work with C/C++ code. Ironically, though, D's superior design has pretty much eliminated the need for scope guards except in a few rare cases. :-P They used to be still useful for things like closing files at the end of the block, but struct dtors have pretty much eliminated that use case as well. But I'd venture to say that in code that uses manual memory management (like game engines), scope guards are a lifesaver. Maybe Manu can chime in here. :) T -- The best compiler is between your ears. -- Michael Abrash
Aug 03 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, August 03, 2013 12:35:22 H. S. Teoh wrote:
 On Sat, Aug 03, 2013 at 12:22:53PM -0700, Walter Bright wrote:
 On 8/3/2013 12:00 PM, JS wrote:
What I really don't get it is why people think that just because they
won't use such a feature then it must be useless to everyone else.

You could provide supporting evidence by examining every use of switch in the dmd, phobos, and druntime source code, and see what percentage of those would benefit from your proposal. Consider, for example, the scope guard statement in D. It is extremely useful - but it is an unusual form (doesn't exist in other languages) and programmers just don't think in those terms. Andrei & I constantly have to work at 'selling' the benefits of it. It still hasn't really caught on.

At least it has caught on with me. :) After learning about scope guards in D, I've been plagued with persistent thoughts of "I wish I could use a scope guard here!" every time I work with C/C++ code. Ironically, though, D's superior design has pretty much eliminated the need for scope guards except in a few rare cases. :-P They used to be still useful for things like closing files at the end of the block, but struct dtors have pretty much eliminated that use case as well.

I'm surprised that you'd miss scope in C++ and yet not use it in D. The only thing that's really missing from C++ that D has that you might use in place of scope is finally. C++ has RAII just like D does. There's a much bigger difference when comparing against languages which don't have RAII (such as Java or C#), but with C++ has RAII. In general, I think that it comes down to a question of whether RAII or scope(exit) is more appropriate, and RAII works better in common cases (such as closing files or releasing a mutex), wheras scope(exit) works better in cases which aren't common (since it doesn't make sense to create types just for those cases). RAII also makes more sense in cases where you essentially need a reference count before doing the action rather than just when exiting the scope (e.g. closing files is also a good example of that; a File struct is more flexible than using scope(exit) to close the file). I definitely use scope from time to time, but I don't know how frequently I use it in comparison to how often I should use it. I was actually using scope(success) more until someone pointed out that there's an efficiency hit with that as it was putting try-catch blocks in places where there wouldn't have been before (as opposed to scope(exit) or scope(failure) where you'd be using try-catch blocks if you weren't using scope). - Jonathan M Davis
Aug 03 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Aug 03, 2013 at 01:33:44PM -0700, Jonathan M Davis wrote:
 On Saturday, August 03, 2013 12:35:22 H. S. Teoh wrote:
 On Sat, Aug 03, 2013 at 12:22:53PM -0700, Walter Bright wrote:


 Consider, for example, the scope guard statement in D. It is
 extremely useful - but it is an unusual form (doesn't exist in
 other languages) and programmers just don't think in those terms.
 Andrei & I constantly have to work at 'selling' the benefits of
 it. It still hasn't really caught on.

At least it has caught on with me. :) After learning about scope guards in D, I've been plagued with persistent thoughts of "I wish I could use a scope guard here!" every time I work with C/C++ code. Ironically, though, D's superior design has pretty much eliminated the need for scope guards except in a few rare cases. :-P They used to be still useful for things like closing files at the end of the block, but struct dtors have pretty much eliminated that use case as well.

I'm surprised that you'd miss scope in C++ and yet not use it in D.

Well, I miss it more in C than C++, but C++'s manual memory management does make scope rather attractive. The same goes for D, actually, but that's largely alleviated due to the built-in GC.
 The only thing that's really missing from C++ that D has that you
 might use in place of scope is finally.

Truth be told, I think scope trumps finally because it localizes the cleanup statement to the initialization. Sprinkling related code across two different places is more fragile and bug-prone.
 C++ has RAII just like D does.  There's a much bigger difference when
 comparing against languages which don't have RAII (such as Java or
 C#), but with C++ has RAII.

Yeah, I think I mostly had C in mind when I wrote what I did. :)
 In general, I think that it comes down to a question of whether RAII
 or scope(exit) is more appropriate, and RAII works better in common
 cases (such as closing files or releasing a mutex), wheras scope(exit)
 works better in cases which aren't common (since it doesn't make sense
 to create types just for those cases). RAII also makes more sense in
 cases where you essentially need a reference count before doing the
 action rather than just when exiting the scope (e.g. closing files is
 also a good example of that; a File struct is more flexible than using
 scope(exit) to close the file).

Yeah, with RAII, much of the use cases of scope is eliminated. I'm mainly working with C at my job right now, which is why I miss scope so much. C is just so tedious to use due to the amount of manual baby-sitting required to make things work properly. I still miss scope in C++ because of the lack of a GC, but otherwise, even C++ doesn't have that many use cases for scope left.
 I definitely use scope from time to time, but I don't know how
 frequently I use it in comparison to how often I should use it. I was
 actually using scope(success) more until someone pointed out that
 there's an efficiency hit with that as it was putting try-catch blocks
 in places where there wouldn't have been before (as opposed to
 scope(exit) or scope(failure) where you'd be using try-catch blocks if
 you weren't using scope).

Hmm, I never thought of that. So that limits the use cases of scope guards even more. :-P T -- My program has no bugs! Only unintentional features...
Aug 03 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, August 03, 2013 14:25:24 H. S. Teoh wrote:
 On Sat, Aug 03, 2013 at 01:33:44PM -0700, Jonathan M Davis wrote:
 The only thing that's really missing from C++ that D has that you
 might use in place of scope is finally.

Truth be told, I think scope trumps finally because it localizes the cleanup statement to the initialization. Sprinkling related code across two different places is more fragile and bug-prone.

Yes. There are lots of places where scope(exit) is far better than finally. It's just that aside from scope statements, the only related feature that C++ lacks is finally (and scope(exit) uses finally underneath the hood).
 C++ has RAII just like D does.  There's a much bigger difference when
 comparing against languages which don't have RAII (such as Java or
 C#), but with C++ has RAII.

Yeah, I think I mostly had C in mind when I wrote what I did. :)

Yeah. The lack of RAII and scope in C is truly painful. I'm very glad that I've never had to write much pure C code.
 I definitely use scope from time to time, but I don't know how
 frequently I use it in comparison to how often I should use it. I was
 actually using scope(success) more until someone pointed out that
 there's an efficiency hit with that as it was putting try-catch blocks
 in places where there wouldn't have been before (as opposed to
 scope(exit) or scope(failure) where you'd be using try-catch blocks if
 you weren't using scope).

[...] Hmm, I never thought of that. So that limits the use cases of scope guards even more. :-P

Yeah. For instance, I'd made it so that RedBlackTree was using scope(success) for mutating its length in a few places, which helped make the code cleaner (because you didn't have to worry about incrementing the length at each of the various return statements), but that introduced try-catch blocks where there otherwise wouldn't have been any, and that code definitely needs to be as efficient as possible, so the scope(success) statements were removed from there. Other code wouldn't care as much, but for something like RedBlackTree, it really matters. It is a bit of a shame though, since it made the code cleaner. - Jonathan M Davis
Aug 03 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Aug 03, 2013 at 02:34:51PM -0700, Jonathan M Davis wrote:
 On Saturday, August 03, 2013 14:25:24 H. S. Teoh wrote:
 On Sat, Aug 03, 2013 at 01:33:44PM -0700, Jonathan M Davis wrote:


 I definitely use scope from time to time, but I don't know how
 frequently I use it in comparison to how often I should use it. I
 was actually using scope(success) more until someone pointed out
 that there's an efficiency hit with that as it was putting
 try-catch blocks in places where there wouldn't have been before
 (as opposed to scope(exit) or scope(failure) where you'd be using
 try-catch blocks if you weren't using scope).

[...] Hmm, I never thought of that. So that limits the use cases of scope guards even more. :-P

Yeah. For instance, I'd made it so that RedBlackTree was using scope(success) for mutating its length in a few places, which helped make the code cleaner (because you didn't have to worry about incrementing the length at each of the various return statements), but that introduced try-catch blocks where there otherwise wouldn't have been any, and that code definitely needs to be as efficient as possible, so the scope(success) statements were removed from there. Other code wouldn't care as much, but for something like RedBlackTree, it really matters. It is a bit of a shame though, since it made the code cleaner.

On second thoughts, why is scope(success) implemented as try/catch? Shouldn't the compiler be able to insert it before the end of each block instead? Stack-unwinding bypasses the end of block code, so the only way you can get there is by successful exit. T -- Error: Keyboard not attached. Press F1 to continue. -- Yoon Ha Lee, CONLANG
Aug 03 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, August 03, 2013 14:49:30 H. S. Teoh wrote:
 On Sat, Aug 03, 2013 at 02:34:51PM -0700, Jonathan M Davis wrote:
 On Saturday, August 03, 2013 14:25:24 H. S. Teoh wrote:
 On Sat, Aug 03, 2013 at 01:33:44PM -0700, Jonathan M Davis wrote:


 I definitely use scope from time to time, but I don't know how
 frequently I use it in comparison to how often I should use it. I
 was actually using scope(success) more until someone pointed out
 that there's an efficiency hit with that as it was putting
 try-catch blocks in places where there wouldn't have been before
 (as opposed to scope(exit) or scope(failure) where you'd be using
 try-catch blocks if you weren't using scope).

[...] Hmm, I never thought of that. So that limits the use cases of scope guards even more. :-P

Yeah. For instance, I'd made it so that RedBlackTree was using scope(success) for mutating its length in a few places, which helped make the code cleaner (because you didn't have to worry about incrementing the length at each of the various return statements), but that introduced try-catch blocks where there otherwise wouldn't have been any, and that code definitely needs to be as efficient as possible, so the scope(success) statements were removed from there. Other code wouldn't care as much, but for something like RedBlackTree, it really matters. It is a bit of a shame though, since it made the code cleaner.

[...] On second thoughts, why is scope(success) implemented as try/catch? Shouldn't the compiler be able to insert it before the end of each block instead? Stack-unwinding bypasses the end of block code, so the only way you can get there is by successful exit.

Hmmm. For a scope(success) statement to work, the code has to be put at every successful exit point from the scope. In the simple case, that means putting it at the end of the try portion of a try-catch block, but the try-catch isn't strictly necessary if there is no scope(failure) or scope(exit) - though I don't know what dmd currently does. Where scope(success) is useful is when you have multiple return statements and want something to occur when they return before exiting the function (or possibly the same thing but with break or continue statements inside a loop). In that case, try-catch doesn't help at all, beacause in all cases, you're forced to either duplicate the code in the scope(success) block at each point that the code exits the scope or have a common block with a goto at each exit point. Yeah. I don't see any need for try-catch there. So, it shouldn't be a problem. I know that it was discussed with regards to a pull for RedBlackTree, but I don't think that it was a long discussion, and I guess that it wasn't long enough. Thinking through it now, I really don't see a problem with it (though maybe I'm missing something). But I'd have to investigate what dmd actually does to see what the actual efficiency impact is. It wouldn't surprise me at all if dmd currently inserts useless try-catch blocks or something like that (though hopefully it doesn't). But assuming that dmd's implementation is appropriately efficient, I don't see any problem with scope(success), so I may start using it again (though I should probably investigate what code it generates first). - Jonathan M Davis
Aug 03 2013
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Aug 03, 2013 at 03:18:49PM -0700, Jonathan M Davis wrote:
[...]
 Hmmm. For a scope(success) statement to work, the code has to be put
 at every successful exit point from the scope. In the simple case,
 that means putting it at the end of the try portion of a try-catch
 block, but the try-catch isn't strictly necessary if there is no
 scope(failure) or scope(exit) - though I don't know what dmd currently
 does.
 
 Where scope(success) is useful is when you have multiple return
 statements and want something to occur when they return before exiting
 the function (or possibly the same thing but with break or continue
 statements inside a loop).  In that case, try-catch doesn't help at
 all, beacause in all cases, you're forced to either duplicate the code
 in the scope(success) block at each point that the code exits the
 scope or have a common block with a goto at each exit point.
 
 Yeah. I don't see any need for try-catch there. So, it shouldn't be a
 problem. 

 I know that it was discussed with regards to a pull for RedBlackTree,
 but I don't think that it was a long discussion, and I guess that it
 wasn't long enough. Thinking through it now, I really don't see a
 problem with it (though maybe I'm missing something). But I'd have to
 investigate what dmd actually does to see what the actual efficiency
 impact is. It wouldn't surprise me at all if dmd currently inserts
 useless try-catch blocks or something like that (though hopefully it
 doesn't). But assuming that dmd's implementation is appropriately
 efficient, I don't see any problem with scope(success), so I may start
 using it again (though I should probably investigate what code it
 generates first).

My guess is that dmd is using the finally block to implement code that runs before the function returns / scope exits. That's probably where the try/catch blocks are coming from. Not terribly efficient, but simpler to implement, I guess. T -- Chance favours the prepared mind. -- Louis Pasteur
Aug 04 2013