www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP 1002 (TryElseExpression) added to the queue

reply Dicebot <public dicebot.lv> writes:
https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

PR: https://github.com/dlang/DIPs/pull/43

Abstract:

In Python, the try/catch/finally syntax is augmented with an 
additional clause, termed else. It is a fantastically useful 
addition to the conventional syntax. It works like this:

```
     try:
         do_something()
     except Exception as e:
         pass # Runs when an error inheriting from Exception was 
raised
     else:
         pass # Runs when no error was raised
     finally:
         pass # Runs unconditionally, evaluates last
```
Sep 27 2016
next sibling parent reply Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Tuesday, September 27, 2016 09:30:10 Dicebot via Digitalmars-d wrote:
 https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

 PR: https://github.com/dlang/DIPs/pull/43

 Abstract:

 In Python, the try/catch/finally syntax is augmented with an
 additional clause, termed else. It is a fantastically useful
 addition to the conventional syntax. It works like this:

 ```
      try:
          do_something()
      except Exception as e:
          pass # Runs when an error inheriting from Exception was
 raised
      else:
          pass # Runs when no error was raised
      finally:
          pass # Runs unconditionally, evaluates last
 ```
And why not just put the code that would go in the else at the end of the try block? Just like with this proposed else, the code would only run if the preceding code didn't throw any exceptions. This just seems like an attempt to make D more like python rather than to add anything useful. - Jonathan M Davis
Sep 27 2016
next sibling parent reply Idan Arye <GenericNPC gmail.com> writes:
On Tuesday, 27 September 2016 at 09:48:42 UTC, Jonathan M Davis 
wrote:
 On Tuesday, September 27, 2016 09:30:10 Dicebot via 
 Digitalmars-d wrote:
 https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

 PR: https://github.com/dlang/DIPs/pull/43

 Abstract:

 In Python, the try/catch/finally syntax is augmented with an 
 additional clause, termed else. It is a fantastically useful 
 addition to the conventional syntax. It works like this:

 ```
      try:
          do_something()
      except Exception as e:
          pass # Runs when an error inheriting from Exception 
 was
 raised
      else:
          pass # Runs when no error was raised
      finally:
          pass # Runs unconditionally, evaluates last
 ```
And why not just put the code that would go in the else at the end of the try block? Just like with this proposed else, the code would only run if the preceding code didn't throw any exceptions. This just seems like an attempt to make D more like python rather than to add anything useful. - Jonathan M Davis
Exceptions thrown in the `else` clause are not caught in the catch/expect clauses. This gives you finer grained control: try { auto f1 = File("f1.txt"); } catch (ErrnoException) { // f1.txt not found? no biggie... } else { // This won't happen if we can't open f1.txt // If we can't open f2 we don't want to catch the exception: auto f2 = File("f2.txt", "w"); // Do stuff with f1 and f2 } // This will still happen even if we can't open f1.txt BTW, if this feature is ever implemented in D, it's important that the else clause will continue the try clause's scope.
Sep 27 2016
parent pineapple <meapineapple gmail.com> writes:
On Tuesday, 27 September 2016 at 10:05:20 UTC, Idan Arye wrote:
 BTW, if this feature is ever implemented in D, it's important 
 that the else clause will continue the try clause's scope.
The catch and finally clauses do currently continue the scope, right? (If they don't, they probably should, too.)
Sep 27 2016
prev sibling parent pineapple <meapineapple gmail.com> writes:
On Tuesday, 27 September 2016 at 09:48:42 UTC, Jonathan M Davis 
wrote:
 And why not just put the code that would go in the else at the 
 end of the try block? Just like with this proposed else, the 
 code would only run if the preceding code didn't throw any 
 exceptions. This just seems like an attempt to make D more like 
 python rather than to add anything useful.

 - Jonathan M Davis
This is a commonly-used tool that makes code more readable and cuts down on programmer error. It's far more concise and digestible than the functional equivalent, which is _not_ to put the code at the end of the `try` block, it's to put it in the `finally` block - refer to the DIP's example for how that works. This is the most important difference between using `else` and doing what you described: Exceptions thrown by the code in the `else` block are not caught by the `catch` statements intended to handle errors by the operation in the `try` block, but not to handle errors resulting from attempting to handle a success state.
Sep 27 2016
prev sibling next sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Tuesday, 27 September 2016 at 09:30:10 UTC, Dicebot wrote:
 https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

 PR: https://github.com/dlang/DIPs/pull/43

 Abstract:

 In Python, the try/catch/finally syntax is augmented with an 
 additional clause, termed else. It is a fantastically useful 
 addition to the conventional syntax. It works like this:

 ```
     try:
         do_something()
     except Exception as e:
         pass # Runs when an error inheriting from Exception was 
 raised
     else:
         pass # Runs when no error was raised
     finally:
         pass # Runs unconditionally, evaluates last
 ```
What's annoying is that we already have finally, which can be reproduced with other language features: { /*finally*/ scope (exit) {} try { do_something(); } catch (Exception e) {} } but we don't (yet) have catch else, which is harder to immitate. Options are: A) the else clause is nothrow (in which case it can just go last inside the try) or B) store a flag and have to use immitation finally: { /*finally*/ scope (exit) {} bool exceptionThrown = false; try { doSomething(); } catch (Exception e) { exceptionThrown = true; } /*else*/ if (!exceptionThrown) {} }
Sep 27 2016
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/27/16 6:55 AM, John Colvin wrote:
 What's annoying is that we already have finally,  which can be
 reproduced with other language features:

 {
     /*finally*/ scope (exit) {}
     try {
         do_something();
     } catch (Exception e) {}
 }
Hm... I always thought scope(exit) is lowered to: try { } finally { // scope exit code here } Which one is the building block? ;)
 but we don't (yet) have catch else, which is harder to immitate. Options
 are:
 A) the else clause is nothrow (in which case it can just go last inside
 the try)
 or
 B) store a flag and have to use immitation finally:

 {
     /*finally*/ scope (exit) {}
     bool exceptionThrown = false;
     try {
         doSomething();
     } catch (Exception e) {
         exceptionThrown = true;
     }
     /*else*/ if (!exceptionThrown) {}
 }
I tried a few things, including scope(success), but it doesn't seem doable without an extra piece of data. Essentially, the else clause allows you to split your try block into catch-protected code, and non-catch-protected code. Seems like a worthwhile addition, if easily implemented. -Steve
Sep 27 2016
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/27/2016 6:22 AM, Steven Schveighoffer wrote:
 Hm... I always thought scope(exit) is lowered to:

 try
 {
 }
 finally
 {
    // scope exit code here
 }

 Which one is the building block? ;)
try/catch/finally is the building block, other constructs are lowered to that.
Sep 27 2016
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Tuesday, 27 September 2016 at 10:55:47 UTC, John Colvin wrote:
 but we don't (yet) have catch else, which is harder to 
 immitate. Options are:
 A) the else clause is nothrow (in which case it can just go 
 last inside the try)
 or
 B) store a flag and have to use immitation finally:

 {
     /*finally*/ scope (exit) {}
     bool exceptionThrown = false;
     try {
         doSomething();
     } catch (Exception e) {
         exceptionThrown = true;
     }
     /*else*/ if (!exceptionThrown) {}
 }
C) Use collectException: import std.exception; auto ex = collectException!MyException(doSomething()); if (ex) handleException(ex); else { // doSomething succeeded ... } collectException could be improved to catch more than one type of exception, returning the common type. Alternatively it could maybe return a tuple of the exception and the 1-based index of which type of exception was thrown.
Sep 30 2016
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/27/2016 2:30 AM, Dicebot wrote:
 https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

 PR: https://github.com/dlang/DIPs/pull/43

 Abstract:

 In Python, the try/catch/finally syntax is augmented with an additional clause,
 termed else. It is a fantastically useful addition to the conventional syntax.
 It works like this:

 ```
     try:
         do_something()
     except Exception as e:
         pass # Runs when an error inheriting from Exception was raised
     else:
         pass # Runs when no error was raised
     finally:
         pass # Runs unconditionally, evaluates last
 ```
The DIP says that a state variable is currently necessary, but that is incorrect: try { scope (exit) { Runs unconditionally, evaluates last } scope (success) { runs when no error was raised } do_something(); } catch (Exception e) { Runs when an error inheriting from Exception was raised } Implementation: The try/catch/else/finally could be 'lowered' into the above form. These references should be included in the DIP: http://dlang.org/spec/statement.html#ScopeGuardStatement http://dlang.org/exception-safe.html My opinion: Due to the existence of the ScopeGuardStatement, I feel this new syntax is redundant and needs a much better justification.
Sep 27 2016
parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 28 September 2016 at 04:23:56 UTC, Walter Bright 
wrote:
 On 9/27/2016 2:30 AM, Dicebot wrote:
 https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

 PR: https://github.com/dlang/DIPs/pull/43

 Abstract:

 In Python, the try/catch/finally syntax is augmented with an 
 additional clause,
 termed else. It is a fantastically useful addition to the 
 conventional syntax.
 It works like this:

 ```
     try:
         do_something()
     except Exception as e:
         pass # Runs when an error inheriting from Exception 
 was raised
     else:
         pass # Runs when no error was raised
     finally:
         pass # Runs unconditionally, evaluates last
 ```
The DIP says that a state variable is currently necessary, but that is incorrect: try { scope (exit) { Runs unconditionally, evaluates last } scope (success) { runs when no error was raised } do_something(); } catch (Exception e) { Runs when an error inheriting from Exception was raised }
That's not the same. Exceptions thrown in the success block can be caught by the catch. That scope (success) block is equivalent to just putting its contents immediately after do_something().
Sep 27 2016
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/27/2016 11:50 PM, John Colvin wrote:
 That's not the same. Exceptions thrown in the success block can be caught by
the
 catch.  That scope (success) block is equivalent to just putting its contents
 immediately after do_something().
Yeah, you're right. I should have tested it. A flag will fix it :-)
Sep 28 2016
prev sibling next sibling parent reply ikod <geller.garry gmail.com> writes:
On Tuesday, 27 September 2016 at 09:30:10 UTC, Dicebot wrote:
 https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

 PR: https://github.com/dlang/DIPs/pull/43

 Abstract:

 In Python, the try/catch/finally syntax is augmented with an 
 additional clause, termed else. It is a fantastically useful 
 addition to the conventional syntax. It works like this:

 ```
     try:
         do_something()
     except Exception as e:
         pass # Runs when an error inheriting from Exception was 
 raised
     else:
         pass # Runs when no error was raised
     finally:
         pass # Runs unconditionally, evaluates last
 ```
Thanks! There is also useful for/else construct in Python https://docs.python.org/2/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops I'd like to see it in D.
Sep 28 2016
parent pineapple <meapineapple gmail.com> writes:
On Wednesday, 28 September 2016 at 07:33:48 UTC, ikod wrote:
 Thanks!

 There is also useful for/else construct in Python

 https://docs.python.org/2/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops

 I'd like to see it in D.
While I appreciate being able to use for/else and while/else in Python, in D using gotos provides a more flexible (if more archaic) solution. But if we were to borrow else from Python for loops - which isn't a terrible idea since gotos are messy and make code harder to read - I'd suggest augmenting the construct with another block that evaluates only when the loop _wasn't_ broken. Make a DIP!
Sep 28 2016
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/27/16 11:30 AM, Dicebot wrote:
 https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

 PR: https://github.com/dlang/DIPs/pull/43

 Abstract:

 In Python, the try/catch/finally syntax is augmented with an additional
 clause, termed else. It is a fantastically useful addition to the
 conventional syntax. It works like this:

 ```
     try:
         do_something()
     except Exception as e:
         pass # Runs when an error inheriting from Exception was raised
     else:
         pass # Runs when no error was raised
     finally:
         pass # Runs unconditionally, evaluates last
 ```
Thanks for the submission. I made on pass through the document and it needs some work. * Please remove colloquialisms. Characterizations such as "fantastically useful" are unlikely to be a convincing motivator and have no place in a DIP. * The motivation section should showcase examples that currently are not possible or are contorted in D, followed by their alternative implementation using the proposed feature. At best, the example would be taken from existing code (e.g. found in dub, phobos, etc). Next best is code that defines a plausible artifact. * The motivation section should also hypothesize on why the feature did not get traction in other languages than Python (Java, C++, C#). Also, it would be useful to show why D does need the feature even though it already has richer exception handing mechanisms by means of "scope". * The "Description" section should be more detailed and less casual. The grammar changes should be shown in a syntax similar to the current grammar definition. * I saw in the forum that the "else" clause is supposed to run in the scope of the "try" statement, but that is not mentioned in the proposal. Even though that is the semantics in Python, that should be explicit in the document. The proposal should be standalone and fully specified without knowing Python or perusing external links. * The fact above (the "else" clause continues the scope of the statement after "try") is surprising, considering that the "catch" and "finally" clauses introduce their own scopes. The irregularity may confuse users. If the "else" clause is defined to introduce its own scope, it seems the advantages of the proposal are diminished. * The "Breaking changes" section should include how the following change in semantics would be addressed. Consider: try if (expression) try { ... } catch (Exception) { ... } else { ... } finally { ... } This code is currently legal and binds the "else" clause to the "if" and the "finally" to the first "try". The proposed feature will bind the "else" and the "finally" to the second try and then probably fail to compile because there is no "catch" or "finally" matching the first "try". * The example by Jack Stouffer should be also shown translated in current and proposed D. * The example with "do_a_thing()" etc. is superfluous because it does not illustrate why one would want to "write code like this". Please focus on examples that are meaningful and easy with the feature, difficult without. * My understanding is the last example (D rendition) can be expressed like this: scope(exit) do_this_always(); bool success; try { do_a_thing(); success = true; } catch(Exception exception) { handle_error(); } finally { if(success) { depends_on_success_of_thing(); } } There are further simplifications if it is known that handle_error() finishes the flow (by either throwing or an early return). Again, motivating examples would at best show that this pattern is frequent enough and awkward enough to justify the language addition. Andrei
Sep 28 2016
next sibling parent Andrea Fontana <nospam example.com> writes:
On Wednesday, 28 September 2016 at 07:47:32 UTC, Andrei 
Alexandrescu wrote:
 scope(exit) do_this_always();
 bool success;
 try
 {
     do_a_thing();
     success = true;
 }
 catch(Exception exception)
 {
     handle_error();
 }
 finally
 {
    if(success)
    {
        depends_on_success_of_thing();
    }
 }
Why not an optional syntax like: finally(bool thrown) { } ?
Sep 28 2016
prev sibling next sibling parent reply pineapple <meapineapple gmail.com> writes:
On Wednesday, 28 September 2016 at 07:47:32 UTC, Andrei 
Alexandrescu wrote:
 * Please remove colloquialisms. Characterizations such as 
 "fantastically useful" are unlikely to be a convincing 
 motivator and have no place in a DIP.

 * The "Description" section should be more detailed and less 
 casual. The grammar changes should be shown in a syntax similar 
 to the current grammar definition.
These were not documented as a requirement anywhere that I saw. I'd have been happy to comply, if I had known this was the practice. I don't know enough about how D is compiled to speak meaningfully about implementation details. I am clearly not the only one who's convinced this is a useful feature. I welcome you or anyone else who can more effectively express the idea to make their own contributions to the DIP. On Wednesday, 28 September 2016 at 07:47:32 UTC, Andrei Alexandrescu wrote:
 * I saw in the forum that the "else" clause is supposed to run 
 in the scope of the "try" statement, but that is not mentioned 
 in the proposal. Even though that is the semantics in Python, 
 that should be explicit in the document. The proposal should be 
 standalone and fully specified without knowing Python or 
 perusing external links.

 * The fact above (the "else" clause continues the scope of the 
 statement after "try") is surprising, considering that the 
 "catch" and "finally" clauses introduce their own scopes. The 
 irregularity may confuse users. If the "else" clause is defined 
 to introduce its own scope, it seems the advantages of the 
 proposal are diminished.
It was an idea that was raised, yes. If catch and finally don't continue the scope of try, then neither should else. That said, it might be preferable if they all did continue try's scope. But this would be a distinct and separate change.
 * The "Breaking changes" section should include how the 
 following change in semantics would be addressed. Consider:

   try
     if (expression)
         try { ... }
         catch (Exception) { ... }
     else { ... }
   finally { ... }

 This code is currently legal and binds the "else" clause to the 
 "if" and the "finally" to the first "try". The proposed feature 
 will bind the "else" and the "finally" to the second try and 
 then probably fail to compile because there is no "catch" or 
 "finally" matching the first "try".
This possibility hadn't occurred to me. Is that really legal? If so, I'd argue the old behavior should be maintained and also that people shouldn't write such ambiguous code.
Sep 28 2016
next sibling parent reply Dicebot <public dicebot.lv> writes:
 protected-headers="v1"
From: Dicebot <public dicebot.lv>
Newsgroups: d,i,g,i,t,a,l,m,a,r,s,.,D
Subject: Re: DIP 1002 (TryElseExpression) added to the queue
References: <gruemzcqaupwptfcbefs forum.dlang.org>
 <nsfsip$25bd$1 digitalmars.com> <laknmragteyowpngvnov forum.dlang.org>
In-Reply-To: <laknmragteyowpngvnov forum.dlang.org>

--xcWsWOhDuBfOOMFtKwXrlwq0F5R9a1Mb5
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

On 09/28/2016 01:17 PM, pineapple wrote:
 On Wednesday, 28 September 2016 at 07:47:32 UTC, Andrei Alexandrescu wr=
ote:
 * Please remove colloquialisms. Characterizations such as
 "fantastically useful" are unlikely to be a convincing motivator and
 have no place in a DIP.

 * The "Description" section should be more detailed and less casual.
 The grammar changes should be shown in a syntax similar to the current=
 grammar definition.
=20 These were not documented as a requirement anywhere that I saw. I'd hav=
e
 been happy to comply, if I had known this was the practice.
As the new DIP process is very young, set of requirements is being fleshed out as we go. Basically what happens is that DIP gets into the queue, Andrei and Walter point out what they don't like and I take notice of it to add to the documented requirements. Merged draft DIPs are not set in stone - Andrei's comment is not sign of immediate rejection but a request to make a PR to improve mentioned thing= s.
 * The "Breaking changes" section should include how the following
 change in semantics would be addressed. Consider:

   try
     if (expression)
         try { ... }
         catch (Exception) { ... }
     else { ... }
   finally { ... }

 This code is currently legal and binds the "else" clause to the "if"
 and the "finally" to the first "try". The proposed feature will bind
 the "else" and the "finally" to the second try and then probably fail
 to compile because there is no "catch" or "finally" matching the first=
 "try".
=20 This possibility hadn't occurred to me. Is that really legal?
Yes. `try` body is a single statement or block and `if/else` is a legal single statement. Same for `if` statement and `try/catch`.
 If so, I'd argue ... that
 people shouldn't write such ambiguous code.
Proposing language change is a serious responsibility and speculations about how developers should or should not write their code have no place there. If something is currently legal, breaking changes sections _must_ provide means to mitigate the damage or proposal should not be accepted no matter how good it is. --xcWsWOhDuBfOOMFtKwXrlwq0F5R9a1Mb5--
Sep 28 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/28/16 7:36 AM, Dicebot wrote:
 Merged draft DIPs are not set in stone - Andrei's comment is not sign of
 immediate rejection but a request to make a PR to improve mentioned things.
It's not a sign of rejection at all! I'm not even discussing the technical merits of the language feature itself. For now I'm looking at ways to make it better. -- Andrei
Sep 28 2016
prev sibling next sibling parent Idan Arye <GenericNPC gmail.com> writes:
On Wednesday, 28 September 2016 at 11:17:05 UTC, pineapple wrote:
 On Wednesday, 28 September 2016 at 07:47:32 UTC, Andrei 
 Alexandrescu wrote:
 * I saw in the forum that the "else" clause is supposed to run 
 in the scope of the "try" statement, but that is not mentioned 
 in the proposal. Even though that is the semantics in Python, 
 that should be explicit in the document. The proposal should 
 be standalone and fully specified without knowing Python or 
 perusing external links.

 * The fact above (the "else" clause continues the scope of the 
 statement after "try") is surprising, considering that the 
 "catch" and "finally" clauses introduce their own scopes. The 
 irregularity may confuse users. If the "else" clause is 
 defined to introduce its own scope, it seems the advantages of 
 the proposal are diminished.
It was an idea that was raised, yes. If catch and finally don't continue the scope of try, then neither should else. That said, it might be preferable if they all did continue try's scope. But this would be a distinct and separate change.
I'm the one who suggested that, and I believe there is a very good reason why `else`'s scope behavior should differ from `catch`'s and `try`'s. `catch` and `finally` should not continue `try`'s scope, because they can run even when `try` did not finish successfully(that's their purpose), which means the variables declared in `try` may or may not be initialized in the `catch` and `finally` blocks. For the same reason it's not useful to have them continue the scope - you can't use the variables declared in them if you don't know whether or not they have been initialized. `else` is different - it is guaranteed to only execute if `try` finished successfully, which means all variables in the `try` block have had their initialization statements executed. Also, it's actually useful to have it continue the scope, because one may want to declare a variable in `try`(so they can `catch` exceptions in it's initialization) but use it in `else`(so the same exceptions in it's usage will bubble up). This has little to do with Python's semantics. Python is an interpreted language so it doesn't bother with scope rules for control statements - either the initialization statement was executed and the variable is initialized, or it wasn't and the variable is not declared. D can not imitate this behavior...
Sep 28 2016
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/28/16 7:17 AM, pineapple wrote:
 These were not documented as a requirement anywhere that I saw. I'd have
 been happy to comply, if I had known this was the practice.
Yah, we're also learning the ropes. Bear with us - this is one of the first DIPs using the new flow.
 I don't know enough about how D is compiled to speak meaningfully about
 implementation details.
I'll formalize this in DIP guide, but some level of implementation discussion is necessary - the more, the better. It has happened in the past (in various languages) that things that seemed sensible were proposed and partially implemented without a clear handle on implementation issues. It would improve the DIP a lot if you collaborated with somebody fluent with implementation issues.
 I am clearly not the only one who's convinced this is a useful feature.
 I welcome you or anyone else who can more effectively express the idea
 to make their own contributions to the DIP.
 If catch and finally don't continue the scope of try, then neither
 should else.
Then I'd say the DIP should discuss the relative advantages and disadvantages compared to the incarnations in other languages. My understanding is it is important for the "else" branch to continue work initiated in the "try" branch. How well does the feature fare without this amenity? It's the kind of question the DIP should address.
 That said, it might be preferable if they all did continue try's scope.
 But this would be a distinct and separate change.
The short answer is that will never happen.
 * The "Breaking changes" section should include how the following
 change in semantics would be addressed. Consider:

   try
     if (expression)
         try { ... }
         catch (Exception) { ... }
     else { ... }
   finally { ... }

 This code is currently legal and binds the "else" clause to the "if"
 and the "finally" to the first "try". The proposed feature will bind
 the "else" and the "finally" to the second try and then probably fail
 to compile because there is no "catch" or "finally" matching the first
 "try".
This possibility hadn't occurred to me. Is that really legal? If so, I'd argue the old behavior should be maintained and also that people shouldn't write such ambiguous code.
For a DIP to be successful, its authors need to be fluent with syntactical matters and be able to enumerate them and how they are supposed to be handled ("else" also works with "static if", "version", and since DIP 1002 itself, other "try" statements). Andrei
Sep 28 2016
prev sibling next sibling parent Dicebot <public dicebot.lv> writes:
 protected-headers="v1"
From: Dicebot <public dicebot.lv>
Newsgroups: d,i,g,i,t,a,l,m,a,r,s,.,D
Subject: Re: DIP 1002 (TryElseExpression) added to the queue
References: <gruemzcqaupwptfcbefs forum.dlang.org>
 <nsfsip$25bd$1 digitalmars.com>
In-Reply-To: <nsfsip$25bd$1 digitalmars.com>

--g0ieH94qlsM10fMUs6go06WMNV6LRdwnQ
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

On 09/28/2016 09:47 AM, Andrei Alexandrescu wrote:
 ...
I have added references to both your and Walter comments to DIP1002 review section: https://github.com/dlang/DIPs/pull/44 --g0ieH94qlsM10fMUs6go06WMNV6LRdwnQ--
Sep 28 2016
prev sibling next sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 28 September 2016 at 07:47:32 UTC, Andrei 
Alexandrescu wrote:
 * The "Breaking changes" section should include how the 
 following change in semantics would be addressed. Consider:

   try
     if (expression)
         try { ... }
         catch (Exception) { ... }
     else { ... }
   finally { ... }

 This code is currently legal and binds the "else" clause to the 
 "if" and the "finally" to the first "try". The proposed feature 
 will bind the "else" and the "finally" to the second try and 
 then probably fail to compile because there is no "catch" or 
 "finally" matching the first "try".
Yeah... that's a pain. How about using different keywords: try { // blah } /*else*/ catch (nothrow) { // on success. }
Sep 28 2016
next sibling parent reply pineapple <meapineapple gmail.com> writes:
I submitted a PR addressing some of the mentioned criticisms: 
https://github.com/dlang/DIPs/pull/46
Sep 28 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/28/16 9:10 AM, pineapple wrote:
 I submitted a PR addressing some of the mentioned criticisms:
 https://github.com/dlang/DIPs/pull/46
Thanks. The Phobos examples compared: (1) // Current unittest { bool ok = true; try { auto r2 = assumeSorted([ 677, 345, 34, 7, 5 ]); debug ok = false; } catch (Throwable) { } assert(ok); } // With try/else unittest { try { auto r2 = assumeSorted([ 677, 345, 34, 7, 5 ]); } catch (Throwable) { } else assert(ok); } // Within existing D unittest { try { auto r2 = assumeSorted([ 677, 345, 34, 7, 5 ]); } catch (Throwable) { return; } assert(0); } (2) // Current bool failed = false; try { auto d = c.get!(int); } catch (Exception e) { //writeln(stderr, e.toString); failed = true; } assert(failed); // :o) // With try/else try { auto d = c.get!(int); } catch (Exception e) { } else { assert(0); // :o) } // Within existing D assertThrown(c.get!(int)); (An argument here may be made that assertThrown is "cheating".) (3) // Current void assertNot(string s) { bool b = false; try { decode(s,DecodeMode.STRICT); } catch (DecodeException e) { b = true; } assert(b,s); } // With try/else void assertNot(string s) { try { decode(s,DecodeMode.STRICT); } catch (DecodeException e) {} else { assert(0, s); } } // With scope void assertNot(string s) { try { scope(success) assert(0, s); decode(s,DecodeMode.STRICT); } catch (DecodeException e) {} } The burden is to make the case that the try/else variant is better than the two others. Andrei
Sep 28 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/28/16 7:40 PM, Andrei Alexandrescu wrote:
 // With scope
 void assertNot(string s)
 {
     try { scope(success) assert(0, s); decode(s,DecodeMode.STRICT); }
     catch (DecodeException e) {}
 }
Sorry, this is not semantically equivalent. Replace with: // With scope void assertNot(string s) { try { decode(s,DecodeMode.STRICT); } catch (DecodeException e) { return; } assert(0, s); } Andrei
Sep 28 2016
parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 28 September 2016 at 23:44:19 UTC, Andrei 
Alexandrescu wrote:
 On 9/28/16 7:40 PM, Andrei Alexandrescu wrote:
 // With scope
 void assertNot(string s)
 {
     try { scope(success) assert(0, s); 
 decode(s,DecodeMode.STRICT); }
     catch (DecodeException e) {}
 }
Sorry, this is not semantically equivalent. Replace with: // With scope void assertNot(string s) { try { decode(s,DecodeMode.STRICT); } catch (DecodeException e) { return; } assert(0, s); } Andrei
Aren't those the same, as assert won't ever throw a DecodeException? Simplest implementation: try { decode(s,DecodeMode.STRICT); assert(0, s); } catch (DecodeException e) {}
Sep 29 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/29/2016 03:49 AM, John Colvin wrote:
 On Wednesday, 28 September 2016 at 23:44:19 UTC, Andrei Alexandrescu wrote:
 On 9/28/16 7:40 PM, Andrei Alexandrescu wrote:
 // With scope
 void assertNot(string s)
 {
     try { scope(success) assert(0, s); decode(s,DecodeMode.STRICT); }
     catch (DecodeException e) {}
 }
Sorry, this is not semantically equivalent. Replace with: // With scope void assertNot(string s) { try { decode(s,DecodeMode.STRICT); } catch (DecodeException e) { return; } assert(0, s); } Andrei
Aren't those the same, as assert won't ever throw a DecodeException? Simplest implementation: try { decode(s,DecodeMode.STRICT); assert(0, s); } catch (DecodeException e) {}
Correct, thanks. -- Andrei
Sep 29 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/28/16 7:58 AM, John Colvin wrote:
 On Wednesday, 28 September 2016 at 07:47:32 UTC, Andrei Alexandrescu wrote:
 * The "Breaking changes" section should include how the following
 change in semantics would be addressed. Consider:

   try
     if (expression)
         try { ... }
         catch (Exception) { ... }
     else { ... }
   finally { ... }

 This code is currently legal and binds the "else" clause to the "if"
 and the "finally" to the first "try". The proposed feature will bind
 the "else" and the "finally" to the second try and then probably fail
 to compile because there is no "catch" or "finally" matching the first
 "try".
Yeah... that's a pain. How about using different keywords: try { // blah } /*else*/ catch (nothrow) { // on success. }
No. Just no ;) The more I think about this submission, I feel like the benefits are quite slim. The else clause is really simply a disabling of all the exception handlers at the end of the function. The uses seem very There are some funky English problems too. For example, should it be valid to use "else" without a catch? This reads weird: try { ... } else { ...} I think probably the else should be invalid without a valid catch clause. Otherwise, you could just use scope(success). The boolean to indicate an exception was thrown is cumbersome, but not horrible. Having the compiler manage the boolean may make this cleaner (e.g. finally(bool thrown)), I like it better than the else suggestion. -Steve
Sep 28 2016
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/28/16 1:56 PM, Steven Schveighoffer wrote:
 The more I think about this submission, I feel like the benefits are
 quite slim. The else clause is really simply a disabling of all the
 exception handlers at the end of the function. The uses seem very
Didn't finish this sentence. "very obscure" -Steve
Sep 28 2016
prev sibling parent reply pineapple <meapineapple gmail.com> writes:
On Wednesday, 28 September 2016 at 17:56:13 UTC, Steven 
Schveighoffer wrote:
 The more I think about this submission, I feel like the 
 benefits are quite slim.
This is not and was not intended to be a glorious, incredible addition to the language. It is meant to shove D a couple inches further in the direction of modern programming constructs. Everywhere a programmer can use `else` instead of mucking about with a boolean success flag and having to make absolutely sure the code intended to handle a success state doesn't and will never be modified to throw an exception that the error handling code isn't designed for means less time spent on tedium, and less opportunity for programmer error. On Wednesday, 28 September 2016 at 17:56:13 UTC, Steven Schveighoffer wrote:
 For example, should it be valid to use "else" without a catch?
Yes. On Wednesday, 28 September 2016 at 17:56:13 UTC, Steven Schveighoffer wrote:
 The boolean to indicate an exception was thrown is cumbersome, 
 but not horrible. Having the compiler manage the boolean may 
 make this cleaner (e.g. finally(bool thrown)), I like it better 
 than the else suggestion.
I think this would be an improvement over the current exception handling, but `else` is a pre-existing concept and making `finally` optionally accept a boolean this way tosses convention on its head, and not in a way I think is desireable. If what you're looking for is a clean solution, `finally(bool)` is definitely not it. Moreover, Idan's suggestions about scope sharing make sense to me and I don't think his line of thinking would be compatible with doing it the way you suggest.
Sep 28 2016
next sibling parent reply pineapple <meapineapple gmail.com> writes:
On Wednesday, 28 September 2016 at 20:18:06 UTC, pineapple wrote:
 This is not and was not intended to be a glorious, incredible 
 addition to the language. It is meant to shove D a couple 
 inches further in the direction of modern programming 
 constructs. Everywhere a programmer can use `else` instead of 
 mucking about with a boolean success flag and having to make 
 absolutely sure the code intended to handle a success state 
 doesn't and will never be modified to throw an exception that 
 the error handling code isn't designed for means less time 
 spent on tedium, and less opportunity for programmer error.
Or, more concisely: Just because we have `for` doesn't mean we reject `foreach`. Just because we have `while` doesn't mean we reject `for`. Just because we have `goto` doesn't mean we reject `while`.
Sep 28 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/28/2016 04:21 PM, pineapple wrote:
 On Wednesday, 28 September 2016 at 20:18:06 UTC, pineapple wrote:
 This is not and was not intended to be a glorious, incredible addition
 to the language. It is meant to shove D a couple inches further in the
 direction of modern programming constructs. Everywhere a programmer
 can use `else` instead of mucking about with a boolean success flag
 and having to make absolutely sure the code intended to handle a
 success state doesn't and will never be modified to throw an exception
 that the error handling code isn't designed for means less time spent
 on tedium, and less opportunity for programmer error.
Or, more concisely: Just because we have `for` doesn't mean we reject `foreach`. Just because we have `while` doesn't mean we reject `for`. Just because we have `goto` doesn't mean we reject `while`.
A DIP should stay as far away from this kind of argument as possible. Redundancy of existing features should not be used as precedent and justification for adding another redundant feature. The right angle here is to successfully present evidence that the frequency of a specific idiom/pattern is high enough to justify adding redundancy. +cc Dicebot to add this to the guidelines Thanks, Andrei
Sep 29 2016
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/29/2016 7:32 AM, Andrei Alexandrescu wrote:
 A DIP should stay as far away from this kind of argument as possible.
Redundancy
 of existing features should not be used as precedent and justification for
 adding another redundant feature.
More generally, a problem with existing feature X is not a justification for introducing more instances of the problem. This line of justification occurs regularly.
Sep 29 2016
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 29.09.2016 19:35, Walter Bright wrote:
 On 9/29/2016 7:32 AM, Andrei Alexandrescu wrote:
 A DIP should stay as far away from this kind of argument as possible.
 Redundancy
 of existing features should not be used as precedent and justification
 for
 adding another redundant feature.
More generally, a problem with existing feature X is not a justification for introducing more instances of the problem. This line of justification occurs regularly.
I posit you often just misunderstand what the argument is: It's more like: restriction A prevents B (B is what you think is bad), but it also prevents C and D (which are desirable), however, it does not even prevent E and F (which are arguably bad). Hence restriction A prevents many valid use cases without even effectively preventing "bad" usages.
Sep 29 2016
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/28/16 4:18 PM, pineapple wrote:
 On Wednesday, 28 September 2016 at 17:56:13 UTC, Steven Schveighoffer
 wrote:
 The more I think about this submission, I feel like the benefits are
 quite slim.
This is not and was not intended to be a glorious, incredible addition to the language. It is meant to shove D a couple inches further in the direction of modern programming constructs. Everywhere a programmer can use `else` instead of mucking about with a boolean success flag
The main question to answer is how big is this "Everywhere". I've never needed it. This obviously isn't proof against, but the situation we are solving here seems very small. Is it worth adding a construct to the language and it seems here we are going to break valid code that already uses else after catch to mean something else?
 On Wednesday, 28 September 2016 at 17:56:13 UTC, Steven Schveighoffer
 wrote:
 For example, should it be valid to use "else" without a catch?
Yes.
Again, try {this} else {that} looks like "try this if it works, else that", which is not what this really does. else only reads right if it follows catch.
 On Wednesday, 28 September 2016 at 17:56:13 UTC, Steven Schveighoffer
 wrote:
 The boolean to indicate an exception was thrown is cumbersome, but not
 horrible. Having the compiler manage the boolean may make this cleaner
 (e.g. finally(bool thrown)), I like it better than the else suggestion.
I think this would be an improvement over the current exception handling, but `else` is a pre-existing concept and making `finally` optionally accept a boolean this way tosses convention on its head, and not in a way I think is desireable. If what you're looking for is a clean solution, `finally(bool)` is definitely not it.
the pre-existing concept may work for Python, but not be OK for D (i.e. breaks valid code). The boolean concept is how you would implement it by hand, why does this toss it on its head? In fact, any code that requires this kind of flow already uses this mechanism, and can basically be updated to use the new concept by simply removing a few lines and changing finally to finally(bool).
 Moreover, Idan's suggestions about scope sharing make sense to me and I
 don't think his line of thinking would be compatible with doing it the
 way you suggest.
Declaring variables that you need in the right scopes is pretty straightforward. Having scopes magically continue around other separate scopes (catch scopes) doesn't look correct. I get why it's desired, but it doesn't look clean at all. -Steve
Sep 28 2016
next sibling parent reply Idan Arye <GenericNPC gmail.com> writes:
On Wednesday, 28 September 2016 at 21:00:00 UTC, Steven 
Schveighoffer wrote:
 Declaring variables that you need in the right scopes is pretty 
 straightforward. Having scopes magically continue around other 
 separate scopes (catch scopes) doesn't look correct. I get why 
 it's desired, but it doesn't look clean at all.

 -Steve
Consider this: try { auto foo = Foo(); } catch (FooCreationException) { // ... } else { foo.doSomethingWithFoo(); } // foo does not exist here versus this: Foo foo; try { foo = Foo(); } catch (FooCreationException) { // ... } else { foo.doSomethingWithFoo(); } // foo exists here - it could be initialized, it could be not...
Sep 28 2016
next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/28/2016 3:12 PM, Idan Arye wrote:
 Consider this:

     try {
         auto foo = Foo();
     } catch (FooCreationException) {
         // ...
     } else {
         foo.doSomethingWithFoo();
     }
I agree with Steven. Having the 'else' continue on with a scope that is already closed by } is very weird and unsettling. You could argue that D already does this with static if: static if (x) { int x; } x = 3; and that disturbs some people. But it is conditional compilation, and no other way around it has been proposed, and it has major benefits. (C++'s static if proposal does not allow this, a decision that I predict they'll come to regret.) Adding more cases of this sort of thing should be approached with great trepidation, and is not justified if it is only a minor improvement.
Sep 28 2016
parent Jack Stouffer <jack jackstouffer.com> writes:
On Thursday, 29 September 2016 at 00:35:47 UTC, Walter Bright 
wrote:
 I agree with Steven. Having the 'else' continue on with a scope 
 that is already closed by } is very weird and unsettling.
Seconded
 But it is conditional compilation, and no other way around it 
 has been proposed, and it has major benefits. (C++'s static if 
 proposal does not allow this, a decision that I predict they'll 
 come to regret.)
The C++ static_if will create a new scope? Huge mistake IMO. The fact that the static if doesn't create a new scope is a trick that's used a lot in D and Phobos specifically. Case in point: https://github.com/dlang/phobos/blob/a5e935370f5de590532bb5d12610c865343f56a9/std/string.d#L5859
 Adding more cases of this sort of thing should be approached 
 with great trepidation, and is not justified if it is only a 
 minor improvement.
I agree; static if is different because it's a compile time feature and not a run time feature.
Sep 29 2016
prev sibling next sibling parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Wednesday, 28 September 2016 at 22:12:27 UTC, Idan Arye wrote:
     Foo foo;
     try {
         foo = Foo();
     } catch (FooCreationException) {
         // ...
     } else {
         foo.doSomethingWithFoo();
     }
     // foo exists here - it could be initialized, it could be 
 not...
And `Foo` could have ` disabled this()`, so you simply _can't_ declare it without initializing it (or use the dirty `Foo foo = Foo.init` workaround). But of course, that's a corner case...
Sep 29 2016
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/29/2016 4:45 AM, Marc Schütz wrote:
 And `Foo` could have ` disabled this()`, so you simply _can't_ declare it
 without initializing it
Foo foo = void;
Sep 29 2016
parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Thursday, 29 September 2016 at 17:47:41 UTC, Walter Bright 
wrote:
 On 9/29/2016 4:45 AM, Marc Schütz wrote:
 And `Foo` could have ` disabled this()`, so you simply _can't_ 
 declare it
 without initializing it
Foo foo = void;
That's even worse. At least Foo.init would be deterministic.
Oct 02 2016
prev sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/28/16 6:12 PM, Idan Arye wrote:
 On Wednesday, 28 September 2016 at 21:00:00 UTC, Steven Schveighoffer
 wrote:
 Declaring variables that you need in the right scopes is pretty
 straightforward. Having scopes magically continue around other
 separate scopes (catch scopes) doesn't look correct. I get why it's
 desired, but it doesn't look clean at all.
Consider this: try { auto foo = Foo(); } catch (FooCreationException) { // ... } else { foo.doSomethingWithFoo(); } // foo does not exist here versus this: Foo foo; try { foo = Foo(); } catch (FooCreationException) { // ... } else { foo.doSomethingWithFoo(); } // foo exists here - it could be initialized, it could be not...
This is what I meant: { Foo foo; try { foo = Foo(); } catch (FooCreationException) { // ... } else { foo.doSomethingWithFoo(); } // foo exists here, but may or may not be correct. Don't use it. // in fact, don't write any code here. } // foo doesn't exist here, just like in other example. -Steve
Sep 29 2016
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Wednesday, 28 September 2016 at 21:00:00 UTC, Steven 
Schveighoffer wrote:
 Moreover, Idan's suggestions about scope sharing make sense to 
 me and I
 don't think his line of thinking would be compatible with 
 doing it the
 way you suggest.
Declaring variables that you need in the right scopes is pretty straightforward. Having scopes magically continue around other separate scopes (catch scopes) doesn't look correct. I get why it's desired, but it doesn't look clean at all.
Assuming for a minute that we want some form of DIP1002, we might be able to extend the `try` scope in an interesting way: try { auto f = foo(); } catch (Exception) { ... } finally (bool ok) { // true if no exception bar(); __guard (ok) f.baz(); f.baz(); // error: f not in scope } Here the guard statement is a runtime check of `ok`, but it has the compile-time effect of enabling the `try` scope to be extended. Obviously this is a bit extreme if it was the only use of the guard statement, but the guard statement could be useful in other situations too (e.g. non-null code checked at compile-time). Note that finally(bool) is more flexible than finally/else as you can interleave code arbitrarily. __guard makes it clearer something special is happening rather than just implicitly extending `try` scope in the `else` clause. Also, 'else' is not clear enough IMO.
Sep 29 2016
next sibling parent reply pineapple <meapineapple gmail.com> writes:
On Thursday, 29 September 2016 at 10:51:01 UTC, Nick Treleaven 
wrote:
 Note that finally(bool) is more flexible than finally/else as 
 you can interleave code arbitrarily. __guard makes it clearer 
 something special is happening rather than just implicitly 
 extending `try` scope in the `else` clause. Also, 'else' is not 
 clear enough IMO.
While I think finally(bool) is a decent approach, the languages that currently integrate this concept into their error handling - Python and Ruby to my knowledge - all use `else`. Clarity is not a good argument, because those who are already proficient in languages other than D will expect the syntax to be consistent with other languages. It would be like some language using foolishly using `elsif instead of `else if`. (Dammit, Perl.)
Sep 29 2016
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/29/16 7:02 AM, pineapple wrote:
 On Thursday, 29 September 2016 at 10:51:01 UTC, Nick Treleaven wrote:
 Note that finally(bool) is more flexible than finally/else as you can
 interleave code arbitrarily. __guard makes it clearer something
 special is happening rather than just implicitly extending `try` scope
 in the `else` clause. Also, 'else' is not clear enough IMO.
While I think finally(bool) is a decent approach, the languages that currently integrate this concept into their error handling - Python and Ruby to my knowledge - all use `else`. Clarity is not a good argument, because those who are already proficient in languages other than D will expect the syntax to be consistent with other languages. It would be like some language using foolishly using `elsif instead of `else if`. (Dammit, Perl.)
In fact, finally(bool) can be extended to: enum ExceptionStatus { success = 0, caughtException = 1, uncaughtException = 2 } finally(ExceptionStatus) Which has also been requested in the past. -Steve
Sep 29 2016
prev sibling parent crimaniak <crimaniak gmail.com> writes:
On Thursday, 29 September 2016 at 10:51:01 UTC, Nick Treleaven 
wrote:
 Assuming for a minute that we want some form of DIP1002, we 
 might be able to extend the `try` scope in an interesting way:

 try {
     auto f = foo();
 }
 catch (Exception) {
     ...
 }
 finally (bool ok) { // true if no exception
     bar();
     __guard (ok) f.baz();
     f.baz(); // error: f not in scope
 }
My 5 cents, let's play: try { ... } catch() { } catch() { } then { // I don't like idea to use 'else' very much. Please, don't use 'else' with try! ... } finally { } let's be more generic try { ... } catch() { } catch() { } then { ... } catch() { } catch() { } then { ... } catch() { } catch() { } ... finally { } (Hello from Javascript! But we have common scope here.) or use guard in a more obvious place try { // in this code exceptions are routed to attached catch() blocks catch(MyException); // yes, this guard looks as stand-alone catch() to avoid new keywords, for example. May be bad idea, I don't know. // oops, in this code MyException ignores attached catch() blocks because of guard } catch() { } catch() { } finally { } or make it again more generic try { // in this code exceptions are routed to attached catch() blocks as usual // ... but now catch() block can also be places inside of try block catch(MyException){ // process // goto finally } // oops, this code below of catch(MyException), so... } catch() { } catch() { } finally { } As for me, last variant is the most straightforward.
Sep 30 2016
prev sibling parent ikod <geller.garry gmail.com> writes:
On Wednesday, 28 September 2016 at 20:18:06 UTC, pineapple wrote:
 On Wednesday, 28 September 2016 at 17:56:13 UTC, Steven 
 Schveighoffer wrote:
 The more I think about this submission, I feel like the 
 benefits are quite slim.
This is not and was not intended to be a glorious, incredible addition to the language. It is meant to shove D a couple inches further in the direction of modern programming constructs. Everywhere a programmer can use `else` instead of mucking about with a boolean success flag and having to make absolutely sure the code intended to handle a success state doesn't and will never be modified to throw an exception that the error handling code isn't designed for means less time spent on tedium, and less opportunity for programmer error.
Agree, programming should be fun, not struggle.
Sep 28 2016
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/28/2016 12:47 AM, Andrei Alexandrescu wrote:
 * Please remove colloquialisms. Characterizations such as "fantastically
useful"
 are unlikely to be a convincing motivator and have no place in a DIP.

 * The motivation section should showcase examples that currently are not
 possible or are contorted in D, followed by their alternative implementation
 using the proposed feature. At best, the example would be taken from existing
 code (e.g. found in dub, phobos, etc). Next best is code that defines a
 plausible artifact.

 * The motivation section should also hypothesize on why the feature did not get
 traction in other languages than Python (Java, C++, C#). Also, it would be
 useful to show why D does need the feature even though it already has richer
 exception handing mechanisms by means of "scope".

 * The "Description" section should be more detailed and less casual. The
grammar
 changes should be shown in a syntax similar to the current grammar definition.

 * [...] The proposal should be standalone and fully specified without knowing
Python or
 perusing external links.

 * [...]  Please focus on
 examples that are meaningful and easy with the feature, difficult without.
These are great suggestions and apply generally. They should be added to the guide on doing a proper DIP.
Sep 28 2016
prev sibling parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Tuesday, 27 September 2016 at 09:30:10 UTC, Dicebot wrote:
 https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

 PR: https://github.com/dlang/DIPs/pull/43

 Abstract:

 In Python, the try/catch/finally syntax is augmented with an 
 additional clause, termed else. It is a fantastically useful 
 addition to the conventional syntax. It works like this:
I support this addition because, while it's possible to mimic this behavior now, this makes code cleaner. I will also post some rationale from the Python docs: "The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try/except statement." https://docs.python.org/3/tutorial/errors.html#handling-exceptions
Sep 28 2016
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/28/16 12:19 PM, Jack Stouffer wrote:
 On Tuesday, 27 September 2016 at 09:30:10 UTC, Dicebot wrote:
 https://github.com/dlang/DIPs/blob/master/DIPs/DIP1002.md

 PR: https://github.com/dlang/DIPs/pull/43

 Abstract:

 In Python, the try/catch/finally syntax is augmented with an
 additional clause, termed else. It is a fantastically useful addition
 to the conventional syntax. It works like this:
I support this addition because, while it's possible to mimic this behavior now, this makes code cleaner.
This rough count: git grep '^ *try' | wc -l reveals 187 uses of "try" in Phobos. Of these, how many could be improved? Looking into that and also on a selection of dub projects would strengthen the argument. Assertions such as "makes the code cleaner" are likely to add value only if backed up by evidence (case studies, realistic examples).
 I will also post some rationale from the Python docs:

 "The use of the else clause is better than adding additional code to the
 try clause because it avoids accidentally catching an exception that
 wasn’t raised by the code being protected by the try/except statement."

 https://docs.python.org/3/tutorial/errors.html#handling-exceptions
Porting motivating arguments from other languages is helpful only if put in the context of D, e.g. Python does not have "scope" statements, which makes matters different across the two languages. Andrei
Sep 28 2016
parent reply Jack Stouffer <jack jackstouffer.com> writes:
On Wednesday, 28 September 2016 at 10:45:11 UTC, Andrei 
Alexandrescu wrote:
 Assertions such as "makes the code cleaner" are likely to add 
 value only if backed up by evidence (case studies, realistic 
 examples).
This is based on my anecdotal experience. I also posted an example in the original thread which was included in the DIP.
 Porting motivating arguments from other languages is helpful 
 only if put in the context of D, e.g. Python does not have 
 "scope" statements, which makes matters different across the 
 two languages.
It was already shown in this thread how scope statements do not achieve the same effect as the try/else statement; the point still stands.
Sep 28 2016
next sibling parent John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 28 September 2016 at 10:50:00 UTC, Jack Stouffer 
wrote:
 On Wednesday, 28 September 2016 at 10:45:11 UTC, Andrei 
 Alexandrescu wrote:
 Assertions such as "makes the code cleaner" are likely to add 
 value only if backed up by evidence (case studies, realistic 
 examples).
This is based on my anecdotal experience. I also posted an example in the original thread which was included in the DIP.
 Porting motivating arguments from other languages is helpful 
 only if put in the context of D, e.g. Python does not have 
 "scope" statements, which makes matters different across the 
 two languages.
It was already shown in this thread how scope statements do not achieve the same effect as the try/else statement; the point still stands.
Yes, scope can't immitate catch else without a flag. It doesn't follow that therefore we need catch else. What realistic code will be made significantly better by having it? Under what circumstances is structuring the code differently or using a flag so unacceptable that a new language feature is worth it? That's the question that needs answering.
Sep 28 2016
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/28/16 6:50 AM, Jack Stouffer wrote:
 On Wednesday, 28 September 2016 at 10:45:11 UTC, Andrei Alexandrescu wrote:
 Assertions such as "makes the code cleaner" are likely to add value
 only if backed up by evidence (case studies, realistic examples).
This is based on my anecdotal experience. I also posted an example in the original thread which was included in the DIP.
 Porting motivating arguments from other languages is helpful only if
 put in the context of D, e.g. Python does not have "scope" statements,
 which makes matters different across the two languages.
It was already shown in this thread how scope statements do not achieve the same effect as the try/else statement; the point still stands.
Thanks, Jack. Here I'm solely focused on making DIP1002 stronger so I've sent a number of suggestions that I believe would improve the proposal. Although you are free to argue here that in fact the proposal already is strong enough, this is not a "minimal requirements" setup in which a DIP is good to go as long as it passes a checklist. The demand here is elastic; the stronger the DIP, the better. Once submitted, if rejected, the only way to propose a similar feature is by authoring a new proposal with a completely novel perspective. So official review is an important milestone with a high bar. -- Andrei
Sep 29 2016
next sibling parent Jack Stouffer <jack jackstouffer.com> writes:
On Thursday, 29 September 2016 at 12:24:31 UTC, Andrei 
Alexandrescu wrote:
 Once submitted, if rejected, the only way to propose a similar 
 feature is by authoring a new proposal with a completely novel 
 perspective. So official review is an important milestone with 
 a high bar. -- Andrei
Ok, I see where you're coming from, you want DIPs to be arguments in and of themselves. I was looking at them from a community prospective, where the DIP is argued on the forms like with module proposals.
Sep 29 2016
prev sibling parent reply pineapple <meapineapple gmail.com> writes:
On Thursday, 29 September 2016 at 11:45:42 UTC, Marc Schütz wrote:
 On Wednesday, 28 September 2016 at 22:12:27 UTC, Idan Arye 
 wrote:
     Foo foo;
     try {
         foo = Foo();
     } catch (FooCreationException) {
         // ...
     } else {
         foo.doSomethingWithFoo();
     }
     // foo exists here - it could be initialized, it could be 
 not...
And `Foo` could have ` disabled this()`, so you simply _can't_ declare it without initializing it (or use the dirty `Foo foo = Foo.init` workaround). But of course, that's a corner case...
This is actually 100% of why I think scope sharing between `try`, `catch`, `finally`, and `else` statements deserves consideration. `Foo` should not have to be mutable or rebindable in order to handle its success or error state in the other statements. On Thursday, 29 September 2016 at 12:24:31 UTC, Andrei Alexandrescu wrote:
 Thanks, Jack. Here I'm solely focused on making DIP1002 
 stronger so I've sent a number of suggestions that I believe 
 would improve the proposal. Although you are free to argue here 
 that in fact the proposal already is strong enough, this is not 
 a "minimal requirements" setup in which a DIP is good to go as 
 long as it passes a checklist. The demand here is elastic; the 
 stronger the DIP, the better. Once submitted, if rejected, the 
 only way to propose a similar feature is by authoring a new 
 proposal with a completely novel perspective. So official 
 review is an important milestone with a high bar. -- Andrei
I do appreciate the feedback, by the way, which is why I submitted the recent PR. One thing I'd point out: You rewrote my rewritten examples without using `else`, but as was stated immediately before I listed those examples:
 The best examples of code that can be more elegantly written 
 using this
`else` clause occur in application logic, such as the example 
described
 above where a values were read from sensors and saved to a 
 server. However,
 there are a few places in Phobos that could be more readable 
 and not
 require success flags if this new syntax were employed.
Sep 29 2016
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/29/2016 09:00 AM, pineapple wrote:
 One thing I'd point out: You rewrote my rewritten examples without using
 `else`, but as was stated immediately before I listed those examples:

 The best examples of code that can be more elegantly written using this
 `else` clause occur in application logic, such as the example described
 above where a values were read from sensors and saved to a server.
 However,
 there are a few places in Phobos that could be more readable and not
 require success flags if this new syntax were employed.
In order to make this kind of argument work, you need evidence. The sensor example is weak because (a) it comes with a rich context that is only vaguely explained; (b) it is not shown translated in current D; (c) it comes from private correspondence - at best it should be from a visible project. As of right now, the argument about application code being more helped than library code is purely speculative. That's why I also suggest looking at dub and github, which contain a good amount of D application code. You'd make a solid point if you showed how a few of those projects can be improved by the use of the proposed feature. Andrei
Sep 29 2016