digitalmars.D - Suggestion: Syntactic sugar for Exception handling in D2
- Ulrik Mikaelsson (30/30) Jun 21 2009 One thing I often encounter in D, and other languages, is functions look...
- =?ISO-8859-1?Q?Tomasz_Sowi=f1ski?= (9/47) Jun 21 2009 I like it. Although it's only sugar you're right -- it helps reading a b...
- =?ISO-8859-1?Q?Tomasz_Sowi=f1ski?= (2/55) Jun 21 2009
- Ulrik Mikaelsson (7/14) Jun 21 2009 Agreed. And while the use-case for if-statements may be rare, I can see ...
- Robert Fraser (3/19) Jun 21 2009 As Tomaz pointed out, this already works for statements (if, while, for,...
- Daniel Keep (5/5) Jun 21 2009 I like the idea from a DRY perspective. That said, it's a bit
- Michiel Helvensteijn (4/5) Jun 21 2009 How so? I don't see anything 'repeated' in the before-case.
- Daniel Keep (4/9) Jun 21 2009 The 'try' keyword is redundant. The presence of any number of catches
- Michiel Helvensteijn (8/15) Jun 22 2009 Ah yes. So the intention to trap exceptions is repeated. If there were n...
- Michel Fortin (50/60) Jun 22 2009 I disagree that 'try' is redundent. I say it resolves an ambiguity. For
- Ulrik Mikaelsson (3/9) Jun 21 2009 To be honest, while the only obvious benefit is shorting down the number...
- Jarrett Billingsley (8/9) Jun 21 2009 If it's braces you're concerned with, D doesn't actually require them
- Ulrik Mikaelsson (2/5) Jun 21 2009 + * Patches adding exception-handling will not change indentation of a...
- Jarrett Billingsley (10/15) Jun 21 2009 ist, I really strive towards patches that are as readable as possible.
- Walter Bright (3/3) Jun 21 2009 I suggest looking at D's scope guard statements, which replace most uses...
- Max Samukha (5/8) Jun 21 2009 I don't think the example provided by the original poster can be
- Ulrik Mikaelsson (3/5) Jun 23 2009 As I said, the braces is just the small obvious benefit. The larger bene...
- Ulrik Mikaelsson (3/5) Jun 23 2009 While scope guards is absolutely the right solution to resource handling...
One thing I often encounter in D, and other languages, is functions looking something like; void myfunc(Obj input) { try { do_something(input); } catch (SomeException e) { handle_error(e); } } While there's no real problem with this code, I have some experience from Ruby, which has added some syntactic sugar regarding this, making all code-blocks a potential "try-clause", if there's a catch-block (or finally). In D, it would look something like (and have the exact same semantic meaning of the code above); void myfunc(Obj input) { do_something(input); } catch (SomeException e) { handle_error(e); } IMHO, this syntactic addition gives a few advantages; * Makes the code slightly more readable, since the "exceptional" code-paths are clearly separated * Biases me as a programmer to think a little bit more of exactly what exceptions can be raised in a function, improving my code-quality. * When I'm about to write a try-clause, makes me think twice if the code could not be extracted as a separate method instead (if I can only figure a good name for it), also improving readability and code-structure. To sum up; while this is purely syntactic sugar, my personal experience from Ruby is that this syntax encourages better coding on my part, which I think would be a good thing to incorporate in D. One thing, I'm pondering though, is exactly in what blocks this should be allowed, and what semantics should apply. * Inner anonymous functions? * If statements? * For-loops? If so, is the try for the entire loop, or per iteration? * How does this relate to the contract-programming-features in D? Comments / opinions on this, anyone?
Jun 21 2009
I like it. Although it's only sugar you're right -- it helps reading a bit. But I would allow (or even require) "try" before a block of code: if (condition) try { ... } catch (Exception ex) { ... } Seeing "try" there cuts down on the gray matter needed to understand what it does. And just not to stray too much from the C-family. Tomek Ulrik Mikaelsson Wrote:One thing I often encounter in D, and other languages, is functions looking something like; void myfunc(Obj input) { try { do_something(input); } catch (SomeException e) { handle_error(e); } } While there's no real problem with this code, I have some experience from Ruby, which has added some syntactic sugar regarding this, making all code-blocks a potential "try-clause", if there's a catch-block (or finally). In D, it would look something like (and have the exact same semantic meaning of the code above); void myfunc(Obj input) { do_something(input); } catch (SomeException e) { handle_error(e); } IMHO, this syntactic addition gives a few advantages; * Makes the code slightly more readable, since the "exceptional" code-paths are clearly separated * Biases me as a programmer to think a little bit more of exactly what exceptions can be raised in a function, improving my code-quality. * When I'm about to write a try-clause, makes me think twice if the code could not be extracted as a separate method instead (if I can only figure a good name for it), also improving readability and code-structure. To sum up; while this is purely syntactic sugar, my personal experience from Ruby is that this syntax encourages better coding on my part, which I think would be a good thing to incorporate in D. One thing, I'm pondering though, is exactly in what blocks this should be allowed, and what semantics should apply. * Inner anonymous functions? * If statements? * For-loops? If so, is the try for the entire loop, or per iteration? * How does this relate to the contract-programming-features in D? Comments / opinions on this, anyone?
Jun 21 2009
Oh God, the example already compiles in D (and a few other languages, I guess). I'm sorry. Tomasz Sowiński Wrote:I like it. Although it's only sugar you're right -- it helps reading a bit. But I would allow (or even require) "try" before a block of code: if (condition) try { ... } catch (Exception ex) { ... } Seeing "try" there cuts down on the gray matter needed to understand what it does. And just not to stray too much from the C-family. Tomek Ulrik Mikaelsson Wrote:One thing I often encounter in D, and other languages, is functions looking something like; void myfunc(Obj input) { try { do_something(input); } catch (SomeException e) { handle_error(e); } } While there's no real problem with this code, I have some experience from Ruby, which has added some syntactic sugar regarding this, making all code-blocks a potential "try-clause", if there's a catch-block (or finally). In D, it would look something like (and have the exact same semantic meaning of the code above); void myfunc(Obj input) { do_something(input); } catch (SomeException e) { handle_error(e); } IMHO, this syntactic addition gives a few advantages; * Makes the code slightly more readable, since the "exceptional" code-paths are clearly separated * Biases me as a programmer to think a little bit more of exactly what exceptions can be raised in a function, improving my code-quality. * When I'm about to write a try-clause, makes me think twice if the code could not be extracted as a separate method instead (if I can only figure a good name for it), also improving readability and code-structure. To sum up; while this is purely syntactic sugar, my personal experience from Ruby is that this syntax encourages better coding on my part, which I think would be a good thing to incorporate in D. One thing, I'm pondering though, is exactly in what blocks this should be allowed, and what semantics should apply. * Inner anonymous functions? * If statements? * For-loops? If so, is the try for the entire loop, or per iteration? * How does this relate to the contract-programming-features in D? Comments / opinions on this, anyone?
Jun 21 2009
Tomasz Sowiński Wrote:I like it. Although it's only sugar you're right -- it helps reading a bit. But I would allow (or even require) "try" before a block of code: if (condition) try { ... } catch (Exception ex) { ... }Agreed. And while the use-case for if-statements may be rare, I can see a few cases in for-loops where it actually makes a little sense, but then it's better to be explicit about it; foreach (item; collection) try { process(item); } catch (StopException e) { break; }
Jun 21 2009
Ulrik Mikaelsson wrote:Tomasz Sowiński Wrote:As Tomaz pointed out, this already works for statements (if, while, for, foreach, with, synchronized, etc.).I like it. Although it's only sugar you're right -- it helps reading a bit. But I would allow (or even require) "try" before a block of code: if (condition) try { ... } catch (Exception ex) { ... }Agreed. And while the use-case for if-statements may be rare, I can see a few cases in for-loops where it actually makes a little sense, but then it's better to be explicit about it; foreach (item; collection) try { process(item); } catch (StopException e) { break; }
Jun 21 2009
I like the idea from a DRY perspective. That said, it's a bit problematic in that you can't tell if any given block has an exception handler until you find the end of it and check. As much as it looks like a nice simplification, I'm not sure this has enough benefit to be worth it.
Jun 21 2009
Daniel Keep wrote:I like the idea from a DRY perspective.How so? I don't see anything 'repeated' in the before-case. -- Michiel Helvensteijn
Jun 21 2009
Michiel Helvensteijn wrote:Daniel Keep wrote:The 'try' keyword is redundant. The presence of any number of catches or a finally indicates that the block must trap exceptions. If there are no catches or a finally, then a try by itself would be pointless.I like the idea from a DRY perspective.How so? I don't see anything 'repeated' in the before-case.
Jun 21 2009
Daniel Keep wrote:Ah yes. So the intention to trap exceptions is repeated. If there were no longer any exceptions to worry about, you would have to remove the "try" keyword as well as the "catch" clauses. I hadn't considered the DRY abbreviation to fit there, but now I see how it could. A bit obscurely, I guess, but still validly. -- Michiel HelvensteijnThe 'try' keyword is redundant. The presence of any number of catches or a finally indicates that the block must trap exceptions. If there are no catches or a finally, then a try by itself would be pointless.I like the idea from a DRY perspective.How so? I don't see anything 'repeated' in the before-case.
Jun 22 2009
On 2009-06-21 21:14:53 -0400, Daniel Keep <daniel.keep.lists gmail.com> said:Michiel Helvensteijn wrote:I disagree that 'try' is redundent. I say it resolves an ambiguity. For instance, it makes a big difference here depending on where you write your 'try': foreach (a; b) try { ... } catch (Exception e) { ... } vs. try foreach (a; b) { ... } catch (Exception e) { ... } With proper indentation and some unnecessary braces removed, it's basically this: try foreach (a; b) ...; catch (Exception e) ...; vs. foreach (a; b) try ...; catch (Exception e) ...; Repeat for other control structures ('while', 'if', 'else') and you'll find that the only place where 'try' can be elided is for standalone blocks not part of any control structure, and for the function body. Also, not all braces create blocks: 'static if', 'version' and 'debug' don't create a block even with braces, so you couldn't add catch after these. I think that consistently requiring 'try' is clearer than making it optional only in some circumstances. That said (throwing another idea into the discussion), I wouldn't be against making braces optional around a function body with only one statement: int f(int i) return i+1; in which case you could also write: int f(int i) try return i+1; catch (Exception e) return 0; -- Michel Fortin michel.fortin michelf.com http://michelf.com/Daniel Keep wrote:The 'try' keyword is redundant. The presence of any number of catches or a finally indicates that the block must trap exceptions. If there are no catches or a finally, then a try by itself would be pointless.I like the idea from a DRY perspective.How so? I don't see anything 'repeated' in the before-case.
Jun 22 2009
To be honest, while the only obvious benefit is shorting down the number of braces slightly, the real benefit I experienced from practicing it in Ruby were a slight change in how I actually think about exception handling. It's very hard to quantify how much benefit it really is, but I agree on that it will make the parsing a bit backwards. If it's a big hassle I don't think it's worth it, but if it can be added easily in some already-existing phase, I think it should be seriously considered. Daniel Keep Wrote:I like the idea from a DRY perspective. That said, it's a bit problematic in that you can't tell if any given block has an exception handler until you find the end of it and check. As much as it looks like a nice simplification, I'm not sure this has enough benefit to be worth it.
Jun 21 2009
On Sun, Jun 21, 2009 at 3:48 PM, Ulrik Mikaelsson<ulrik.mikaelsson gmail.com> wrote:To be honest, while the only obvious benefit is shorting down the number of braces slightly, the real benefit I experienced from practicing it in Ruby were a slight change in how I actually think about exception handling.If it's braces you're concerned with, D doesn't actually require them on try/catch/finally like many other languages: try doSomething(input) catch(Exception e) handleError(e);
Jun 21 2009
I just remembered another tiny benefit of allowing this. Being a VCS-fascist, I really strive towards patches that are as readable as possible.* Makes the code slightly more readable, since the "exceptional" code-paths are clearly separated * Biases me as a programmer to think a little bit more of exactly what exceptions can be raised in a function, improving my code-quality. * When I'm about to write a try-clause, makes me think twice if the code could not be extracted as a separate method instead (if I can only figure a good name for it), also improving readability and code-structure.+ * Patches adding exception-handling will not change indentation of a potentially very large method, making it slightly easier to read.
Jun 21 2009
On Sun, Jun 21, 2009 at 3:51 PM, Ulrik Mikaelsson<ulrik.mikaelsson gmail.com> wrote:I just remembered another tiny benefit of allowing this. Being a VCS-fasc=ist, I really strive towards patches that are as readable as possible.e-paths are clearly separated=A0 * Makes the code slightly more readable, since the "exceptional" cod=at exceptions can be raised in a function, improving my code-quality.=A0 * Biases me as a programmer to think a little bit more of exactly wh=code could not be extracted as a separate method instead (if I can only fig= ure a good name for it), also improving readability and code-structure.=A0 * When I'm about to write a try-clause, makes me think twice if the =+ =A0 * Patches adding exception-handling will not change indentation of =a potentially very large method, making it slightly easier to read.Not to deflate you, but most respectable source diff tools I've seen have an option to ignore whitespace/indentation changes :\
Jun 21 2009
I suggest looking at D's scope guard statements, which replace most uses of try statements. http://www.digitalmars.com/d/1.0/statement.html#ScopeGuardStatement
Jun 21 2009
On Sun, 21 Jun 2009 13:14:17 -0700, Walter Bright <newshound1 digitalmars.com> wrote:I suggest looking at D's scope guard statements, which replace most uses of try statements. http://www.digitalmars.com/d/1.0/statement.html#ScopeGuardStatementI don't think the example provided by the original poster can be implemented with scope guards because it's impossible to access the exception object in scope(failure).
Jun 21 2009
If it's braces you're concerned with, D doesn't actually require them on try/catch/finally like many other languages:As I said, the braces is just the small obvious benefit. The larger benefit IMHO is the less obvious shift in how you think about exceptions, but I'm not sure that argument is worth anything if you haven't experienced it personally. Writing braces is even done automatically by some editors, but thinking of exception handling as a natural part of a method (just like in/out contracts are part of the method, and unittests/invariants are a natural part of a class). It's about how the language encourages the developer to think about certain aspects, and that is of course almost impossible to really assess the value of.
Jun 23 2009
I suggest looking at D's scope guard statements, which replace most uses of try statements.While scope guards is absolutely the right solution to resource handling and transactions, I don't see how to use it for some other common uses of exceptions where you need a reference to the exception that was thrown such as error-logging, and exception wrapping. As I've written in a few other places in the thread now, it's not about lacking other solutions to the problem. Scope guards and the existing exception-handling do cover all possible cases. It's neither about fear of wearing out my bracket-keys. It's merely about readability, and slightly shifting how the language affect how developers think about exception handling, trying to make exception-cases a natural but separate part of each method (1). I think I'm already seeing that same reasoing for a few other features in D, such as the contract and unittest-constructs in the language. But those values are highly subjective, and how the language affect the mindset is also very difficult to assess and value without working with it for a while. 1) I've completely abandoned the idea for other blocks than methods. It was a bad idea from start, just ambiguous and doesn't make sense at all.
Jun 23 2009