digitalmars.D - static try catch construct would be helpful
- Bill Baxter (53/53) Feb 25 2008 When plugging types together sometimes you find this one is missing a
- Robert Fraser (9/78) Feb 25 2008 I like it, although I'm not sure how difficult that'd be to implement in...
- Bill Baxter (5/84) Feb 25 2008 And those could be combined with static ifs, too right?
- Robert Fraser (5/93) Feb 26 2008 Well, because of the way the parser words, I'd assume they could be
- Jason House (8/77) Feb 26 2008 This starts to sound a lot like SFINAE from templates. Maybe there's a ...
- Bill Baxter (10/90) Feb 26 2008 Yeh, I think that was more about forcing a SFINAE error, which would
- Bruno Medeiros (13/27) Mar 26 2008 I don't understand this. Why is it difficult to use an is-expression to
- Koroskin Denis (73/95) Mar 26 2008 e =
- Janice Caron (2/2) Mar 26 2008 Useful though static try/catch would be, I'd like to see static
-
Koroskin Denis
(25/27)
Mar 26 2008
On Wed, 26 Mar 2008 18:14:18 +0300, Janice Caron
- Bruno Medeiros (14/85) Mar 27 2008 The divide by zero case actually works with an is-expression (that is,
When plugging types together sometimes you find this one is missing a member or that one defines it in a different way than you expect or maybe a function with some signature isn't supported. What you'd like to do is say "compile this block if you can -- otherwise leave it out" It's like try-catch, but compile-time. Except you don't really want a 'catch'. It's more like an 'else'. So I propose a new form of static: static if { // some code } else static if { // other code } else { // last resort code } The idea is: if "some code" compiles, then use that, otherwise try "other code", and finally if none of the other code blocks compiles, use the else block. And of course it could be mix-n-matched with regular static if()'s. ------ Here's a motivating example taken from real code where I was wrapping one struct with another. The Inner type may or may not support a particular signature of the "doSomething" function. struct Outer(Inner) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } ... Inner _inner; } Currently, the best way I've found to conditionalize that is: static if(is(typeof(_inner.doSomething(1,1,1,1)))) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } } Maybe there's a better way to write that one.. I'm not sure. But the signature of the thing that may or may not exist can be arbitrarily complex. It becomes difficult to think of an is-expression that can test for what you want. You can probably break out the test into a separate template and make it so you can do static if(is(DoSomeCheck!(....)) but writing that DoSomeCheck is annoying too and starts to clutter your source with lots of one-off gobbledy gook templates. I think "argument-less static if blocks" would handle such cases nicely. There's a slight issue in that it could be pretty hard to debug with compiler errors being silently ignored, but that happens currently with the expressions inside "static if(is(...))" already. --bb
Feb 25 2008
Bill Baxter wrote:When plugging types together sometimes you find this one is missing a member or that one defines it in a different way than you expect or maybe a function with some signature isn't supported. What you'd like to do is say "compile this block if you can -- otherwise leave it out" It's like try-catch, but compile-time. Except you don't really want a 'catch'. It's more like an 'else'. So I propose a new form of static: static if { // some code } else static if { // other code } else { // last resort code } The idea is: if "some code" compiles, then use that, otherwise try "other code", and finally if none of the other code blocks compiles, use the else block. And of course it could be mix-n-matched with regular static if()'s. ------ Here's a motivating example taken from real code where I was wrapping one struct with another. The Inner type may or may not support a particular signature of the "doSomething" function. struct Outer(Inner) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } ... Inner _inner; } Currently, the best way I've found to conditionalize that is: static if(is(typeof(_inner.doSomething(1,1,1,1)))) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } } Maybe there's a better way to write that one.. I'm not sure. But the signature of the thing that may or may not exist can be arbitrarily complex. It becomes difficult to think of an is-expression that can test for what you want. You can probably break out the test into a separate template and make it so you can do static if(is(DoSomeCheck!(....)) but writing that DoSomeCheck is annoying too and starts to clutter your source with lots of one-off gobbledy gook templates. I think "argument-less static if blocks" would handle such cases nicely. There's a slight issue in that it could be pretty hard to debug with compiler errors being silently ignored, but that happens currently with the expressions inside "static if(is(...))" already. --bbI like it, although I'm not sure how difficult that'd be to implement in the DMDFE's current model. votes++, under the stipulation that all code in question must be syntactically correct, even if it's not semantically correct. Personally, I like "static try { } else static try { } else { }", which I think conveys the meaning better than static if. Also, I think there should definitely be a strong caution on the specs page that other methods should be tried first, since, as you mentioned, it can spuriously compile the wrong thing if you accidentally have an error there.
Feb 25 2008
Robert Fraser wrote:Bill Baxter wrote:And those could be combined with static ifs, too right? static try { ... } else static if (is(T==blah)) { ... } else static try { ... }. --bbWhen plugging types together sometimes you find this one is missing a member or that one defines it in a different way than you expect or maybe a function with some signature isn't supported. What you'd like to do is say "compile this block if you can -- otherwise leave it out" It's like try-catch, but compile-time. Except you don't really want a 'catch'. It's more like an 'else'. So I propose a new form of static: static if { // some code } else static if { // other code } else { // last resort code } The idea is: if "some code" compiles, then use that, otherwise try "other code", and finally if none of the other code blocks compiles, use the else block. And of course it could be mix-n-matched with regular static if()'s. ------ Here's a motivating example taken from real code where I was wrapping one struct with another. The Inner type may or may not support a particular signature of the "doSomething" function. struct Outer(Inner) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } ... Inner _inner; } Currently, the best way I've found to conditionalize that is: static if(is(typeof(_inner.doSomething(1,1,1,1)))) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } } Maybe there's a better way to write that one.. I'm not sure. But the signature of the thing that may or may not exist can be arbitrarily complex. It becomes difficult to think of an is-expression that can test for what you want. You can probably break out the test into a separate template and make it so you can do static if(is(DoSomeCheck!(....)) but writing that DoSomeCheck is annoying too and starts to clutter your source with lots of one-off gobbledy gook templates. I think "argument-less static if blocks" would handle such cases nicely. There's a slight issue in that it could be pretty hard to debug with compiler errors being silently ignored, but that happens currently with the expressions inside "static if(is(...))" already. --bbI like it, although I'm not sure how difficult that'd be to implement in the DMDFE's current model. votes++, under the stipulation that all code in question must be syntactically correct, even if it's not semantically correct. Personally, I like "static try { } else static try { } else { }", which I think conveys the meaning better than static if. Also, I think there should definitely be a strong caution on the specs page that other methods should be tried first, since, as you mentioned, it can spuriously compile the wrong thing if you accidentally have an error there.
Feb 25 2008
Bill Baxter wrote:Robert Fraser wrote:Well, because of the way the parser words, I'd assume they could be combined with any compile-time construct: static try { } else static if(...) { } else version(...) { } else debug(...) { } else { }Bill Baxter wrote:And those could be combined with static ifs, too right? static try { ... } else static if (is(T==blah)) { ... } else static try { ... }. --bbWhen plugging types together sometimes you find this one is missing a member or that one defines it in a different way than you expect or maybe a function with some signature isn't supported. What you'd like to do is say "compile this block if you can -- otherwise leave it out" It's like try-catch, but compile-time. Except you don't really want a 'catch'. It's more like an 'else'. So I propose a new form of static: static if { // some code } else static if { // other code } else { // last resort code } The idea is: if "some code" compiles, then use that, otherwise try "other code", and finally if none of the other code blocks compiles, use the else block. And of course it could be mix-n-matched with regular static if()'s. ------ Here's a motivating example taken from real code where I was wrapping one struct with another. The Inner type may or may not support a particular signature of the "doSomething" function. struct Outer(Inner) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } ... Inner _inner; } Currently, the best way I've found to conditionalize that is: static if(is(typeof(_inner.doSomething(1,1,1,1)))) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } } Maybe there's a better way to write that one.. I'm not sure. But the signature of the thing that may or may not exist can be arbitrarily complex. It becomes difficult to think of an is-expression that can test for what you want. You can probably break out the test into a separate template and make it so you can do static if(is(DoSomeCheck!(....)) but writing that DoSomeCheck is annoying too and starts to clutter your source with lots of one-off gobbledy gook templates. I think "argument-less static if blocks" would handle such cases nicely. There's a slight issue in that it could be pretty hard to debug with compiler errors being silently ignored, but that happens currently with the expressions inside "static if(is(...))" already. --bbI like it, although I'm not sure how difficult that'd be to implement in the DMDFE's current model. votes++, under the stipulation that all code in question must be syntactically correct, even if it's not semantically correct. Personally, I like "static try { } else static try { } else { }", which I think conveys the meaning better than static if. Also, I think there should definitely be a strong caution on the specs page that other methods should be tried first, since, as you mentioned, it can spuriously compile the wrong thing if you accidentally have an error there.
Feb 26 2008
Bill Baxter wrote:When plugging types together sometimes you find this one is missing a member or that one defines it in a different way than you expect or maybe a function with some signature isn't supported. What you'd like to do is say "compile this block if you can -- otherwise leave it out" It's like try-catch, but compile-time. Except you don't really want a 'catch'. It's more like an 'else'. So I propose a new form of static: static if { // some code } else static if { // other code } else { // last resort code } The idea is: if "some code" compiles, then use that, otherwise try "other code", and finally if none of the other code blocks compiles, use the else block. And of course it could be mix-n-matched with regular static if()'s. ------ Here's a motivating example taken from real code where I was wrapping one struct with another. The Inner type may or may not support a particular signature of the "doSomething" function. struct Outer(Inner) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } ... Inner _inner; } Currently, the best way I've found to conditionalize that is: static if(is(typeof(_inner.doSomething(1,1,1,1)))) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } } Maybe there's a better way to write that one.. I'm not sure. But the signature of the thing that may or may not exist can be arbitrarily complex. It becomes difficult to think of an is-expression that can test for what you want. You can probably break out the test into a separate template and make it so you can do static if(is(DoSomeCheck!(....)) but writing that DoSomeCheck is annoying too and starts to clutter your source with lots of one-off gobbledy gook templates. I think "argument-less static if blocks" would handle such cases nicely. There's a slight issue in that it could be pretty hard to debug with compiler errors being silently ignored, but that happens currently with the expressions inside "static if(is(...))" already. --bbThis starts to sound a lot like SFINAE from templates. Maybe there's a way to write it up that way or combine a proposal with how to modify how templates are used? IIRC, there was past discussion about modifications to how templates handled errors. I do like the idea of static try{} with else clauses. Would it be practical to make the static try only spill over with static assert failures? (to keep error cases under control)
Feb 26 2008
Jason House wrote:Bill Baxter wrote:Yeh, I think that was more about forcing a SFINAE error, which would still be nice to have.When plugging types together sometimes you find this one is missing a member or that one defines it in a different way than you expect or maybe a function with some signature isn't supported. What you'd like to do is say "compile this block if you can -- otherwise leave it out" It's like try-catch, but compile-time. Except you don't really want a 'catch'. It's more like an 'else'. So I propose a new form of static: static if { // some code } else static if { // other code } else { // last resort code } The idea is: if "some code" compiles, then use that, otherwise try "other code", and finally if none of the other code blocks compiles, use the else block. And of course it could be mix-n-matched with regular static if()'s. ------ Here's a motivating example taken from real code where I was wrapping one struct with another. The Inner type may or may not support a particular signature of the "doSomething" function. struct Outer(Inner) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } ... Inner _inner; } Currently, the best way I've found to conditionalize that is: static if(is(typeof(_inner.doSomething(1,1,1,1)))) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } } Maybe there's a better way to write that one.. I'm not sure. But the signature of the thing that may or may not exist can be arbitrarily complex. It becomes difficult to think of an is-expression that can test for what you want. You can probably break out the test into a separate template and make it so you can do static if(is(DoSomeCheck!(....)) but writing that DoSomeCheck is annoying too and starts to clutter your source with lots of one-off gobbledy gook templates. I think "argument-less static if blocks" would handle such cases nicely. There's a slight issue in that it could be pretty hard to debug with compiler errors being silently ignored, but that happens currently with the expressions inside "static if(is(...))" already. --bbThis starts to sound a lot like SFINAE from templates. Maybe there's a way to write it up that way or combine a proposal with how to modify how templates are used? IIRC, there was past discussion about modifications to how templates handled errors.I do like the idea of static try{} with else clauses. Would it be practical to make the static try only spill over with static assert failures? (to keep error cases under control)I don't think so. Having to put the error-causing thing inside an assert would mean you have to make it an expression. If you had such an expression for the condition you want to test, then you could just put it in a static if -- "static if (is(theExpression))". So I don't think there'd be much point of having the feature if it only worked inside static assert(). --bb
Feb 26 2008
Bill Baxter wrote:Currently, the best way I've found to conditionalize that is: static if(is(typeof(_inner.doSomething(1,1,1,1)))) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } } Maybe there's a better way to write that one.. I'm not sure. But the signature of the thing that may or may not exist can be arbitrarily complex. It becomes difficult to think of an is-expression that can test for what you want.I don't understand this. Why is it difficult to use an is-expression to test the condition you are checking? If you're just checking to see if a member exists, you can just do static if(is(typeof(_inner.doSomething))) { If you're checking for the existence of a particular overload, then you will need an expression where that function overload is called. Perhaps the problem is code duplication? (like having two function calls, such as "_inner.doSomething(1,1,1,1)" and "_inner.doSomething(a,b,c,d)" ? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Mar 26 2008
On Wed, 26 Mar 2008 16:30:53 +0300, Bruno Medeiros = <brunodomedeiros+spam com.gmail> wrote:Bill Baxter wrote:e =Currently, the best way I've found to conditionalize that is: static if(is(typeof(_inner.doSomething(1,1,1,1)))) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } } Maybe there's a better way to write that one.. I'm not sure. But th=signature of the thing that may or may not exist can be arbitrarily ==complex. It becomes difficult to think of an is-expression that can =o =test for what you want.I don't understand this. Why is it difficult to use an is-expression t=test the condition you are checking? If you're just checking to see if=a =member exists, you can just do static if(is(typeof(_inner.doSomething))) { If you're checking for the existence of a particular overload, then yo=u =will need an expression where that function overload is called. Perhaps the problem is code duplication? (like having two function =calls, such as "_inner.doSomething(1,1,1,1)" and ="_inner.doSomething(a,b,c,d)" ?Well, I can think of a more sophisticated examples: template invert(real arg) { const real invert =3D 1/arg; } unittest { static try { real success =3D invert!(1); real failure =3D invert!(0); static assert(false); // should not get here } static catch (CT_DivideByZeroException e) // CT for Compile-Time { pragma(msg, e.toString()); // should print DivideByZeroExceptio= n } } template wrong_factorial(int i) { const int wrong_factorial =3D i * wrong_factorial!(i-1); } unittest { static try { const int f =3D wrong_factorial!(1); static assert(false); } static catch (CT_Exception e) { pragma(msg, e.toString()); // should print "CT Stack overflow"= or = "CT Nested loop is too deep" } } or even template SomeFunc(T) { static if (!is(T : Object)) // should only be invoked with referen= ce = types { static throw new CT_Exception("Incompatible Type"); } ... } unittest { static try { alias SomeFunc!(int) SomeFuncInt; SomeFuncInt(); static assert(false); } static catch(CT_AssertionFailureExpection e) { // failure } static catch(CT_Exception e) { pragma(msg, e.toString()); // success } }
Mar 26 2008
Useful though static try/catch would be, I'd like to see static switch/case, static for, static while, and static foreach first.
Mar 26 2008
On Wed, 26 Mar 2008 18:14:18 +0300, Janice Caron <caron800 googlemail.co= m> = wrote:Useful though static try/catch would be, I'd like to see static switch/case, static for, static while, and static foreach first.Or just "static" keyword: static { switch (i) { case 1: doSomeThing(); case 2: doSomeThingElse(); } } static assert(value); <=3D> static { assert(value); } static if (condition) { static { /* ... */ <=3D> if (condition) { /* ... */ } } } Just like debug: debug writefln("%s", value); <=3D> debug { writefln("%s", value); } Fits nicely! :) (Hope, you use fixed-width fonts)
Mar 26 2008
Koroskin Denis wrote:On Wed, 26 Mar 2008 16:30:53 +0300, Bruno Medeiros <brunodomedeiros+spam com.gmail> wrote:The divide by zero case actually works with an is-expression (that is, the is-expression returns false if such compile time error occurs there). I don't think it's something that is clearly defined in the spec tough, so I don't know how much this behavior can be relied on. The wrong factorial case on the other hand, doesn't work. If it is in an is-expression there will always be a recursive expansion compiler error. In any case, I see little or no usefulness in being able to detect/catch such extreme compiler errors. It just seems bad structure, and it is something that not even in runtime I would recommend doing (catching Divide by Zero or Stack Overflow errors). -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DBill Baxter wrote:Well, I can think of a more sophisticated examples: template invert(real arg) { const real invert = 1/arg; } unittest { static try { real success = invert!(1); real failure = invert!(0); static assert(false); // should not get here } static catch (CT_DivideByZeroException e) // CT for Compile-Time { pragma(msg, e.toString()); // should print DivideByZeroException } } template wrong_factorial(int i) { const int wrong_factorial = i * wrong_factorial!(i-1); } unittest { static try { const int f = wrong_factorial!(1); static assert(false); } static catch (CT_Exception e) { pragma(msg, e.toString()); // should print "CT Stack overflow" or "CT Nested loop is too deep" } } or evenCurrently, the best way I've found to conditionalize that is: static if(is(typeof(_inner.doSomething(1,1,1,1)))) { void doSomething(int a, int b, int c, int d) { _inner.doSomething(a,b,c,d); // do something else here } } Maybe there's a better way to write that one.. I'm not sure. But the signature of the thing that may or may not exist can be arbitrarily complex. It becomes difficult to think of an is-expression that can test for what you want.I don't understand this. Why is it difficult to use an is-expression to test the condition you are checking? If you're just checking to see if a member exists, you can just do static if(is(typeof(_inner.doSomething))) { If you're checking for the existence of a particular overload, then you will need an expression where that function overload is called. Perhaps the problem is code duplication? (like having two function calls, such as "_inner.doSomething(1,1,1,1)" and "_inner.doSomething(a,b,c,d)" ?
Mar 27 2008