Re: Safety/purity and assert/enforce error messages
On Thu, Sep 12, 2013 at 09:12:18PM +0200, bearophile wrote: H. S. Teoh: In phobos git HEAD, std.format has been made pure @safe nothrow (and CTFE-able), so you should be able to write your assert as: assert(condition, format(x = %s, blahblah, x)); With the latest DMD from updated GIT head: import std.string: format; void main() pure nothrow { string x = hello; bool condition = true; assert(condition, format(x = %s, blahblah, x)); } It gives: test.d(5): Error: 'std.string.format!(char, string).format' is not nothrow test.d(2): Error: function 'D main' is nothrow yet may throw [...] Oops. Apparently I wrote nothrow but forgot to test it. I did test pure and @safe, though, so at least those two should work. T -- Food and laptops don't mix.
Re: Safety/purity and assert/enforce error messages
On Thursday, September 12, 2013 13:21:26 H. S. Teoh wrote: On Thu, Sep 12, 2013 at 04:07:24PM -0400, Jonathan M Davis wrote: On Thursday, September 12, 2013 12:42:34 H. S. Teoh wrote: On Thu, Sep 12, 2013 at 09:12:18PM +0200, bearophile wrote: H. S. Teoh: In phobos git HEAD, std.format has been made pure @safe nothrow (and CTFE-able), so you should be able to write your assert as: assert(condition, format(x = %s, blahblah, x)); With the latest DMD from updated GIT head: import std.string: format; void main() pure nothrow { string x = hello; bool condition = true; assert(condition, format(x = %s, blahblah, x)); } It gives: test.d(5): Error: 'std.string.format!(char, string).format' is not nothrow test.d(2): Error: function 'D main' is nothrow yet may throw [...] Oops. Apparently I wrote nothrow but forgot to test it. I did test pure and @safe, though, so at least those two should work. format can't be nothrow, because it throws when you screw up the format specifiers. You have to wrap it in a try-catch block and assert(0) in the catch block if you want to put it in a nothrow function. std.datetime does this in at least a few places. [...] Right. Makes me wanna suggest adding this template to std.exception: auto assumeWontThrow(alias fun, T...)(T args) nothrow { try { return fun(args); } catch(Exception) { // You broke your promise, I die. assert(0); } } Then you can write things like: int mayThrow(int arg) { if (arg 0) throw new Exception(...); return BBN(arg); } int iWontThrow() nothrow { // -- N.B. this function is nothrow static assert(123 0); return assumeWontThrow!mayThrow(123); } Sounds like a good suggestion, though an actual implementation should have an error message in the assert(0). You could also implement it as a lazy parameter like enforce and assertNotThrown do (which I think is more user- friendly), but that would likely be less efficient due to how lazy doesn't get optimized very well (or at least, it's my understanding that it doesn't). - Jonathan M Davis
Re: Safety/purity and assert/enforce error messages
On Thu, Sep 12, 2013 at 10:17:30PM +0200, Joseph Rushton Wakeling wrote: On 12/09/13 22:07, Jonathan M Davis wrote: format can't be nothrow, because it throws when you screw up the format specifiers. You have to wrap it in a try-catch block and assert(0) in the catch block if you want to put it in a nothrow function. std.datetime does this in at least a few places. The annoyance of this is that it means that any otherwise @safe pure nothrow function that has an assert() in it can be blocked from being nothrow if it needs a formatted string for the assert failure message. Note that this restriction still applies even if the code is being compiled with -release and the assertion therefore stripped out. Or am I missing a trick as to how to deal with assert() and enforce() ... ? :-) Using assumeWontThrow, as defined in my previous post, you can write this: auto myFunc(int x) nothrow { // Look, ma! This line doesn't violate nothrow! assert(isValid(x), assumeWontThrow!format( Invalid args (%s), dude!, x)); ... // do work here } :-) T -- Uhh, I'm still not here. -- KD, while away on ICQ.
Re: Safety/purity and assert/enforce error messages
H. S. Teoh: In phobos git HEAD, std.format has been made pure @safe nothrow (and CTFE-able), so you should be able to write your assert as: assert(condition, format(x = %s, blahblah, x)); With the latest DMD from updated GIT head: import std.string: format; void main() pure nothrow { string x = hello; bool condition = true; assert(condition, format(x = %s, blahblah, x)); } It gives: test.d(5): Error: 'std.string.format!(char, string).format' is not nothrow test.d(2): Error: function 'D main' is nothrow yet may throw Bye, bearophile
Re: Safety/purity and assert/enforce error messages
On Thursday, September 12, 2013 12:42:34 H. S. Teoh wrote: On Thu, Sep 12, 2013 at 09:12:18PM +0200, bearophile wrote: H. S. Teoh: In phobos git HEAD, std.format has been made pure @safe nothrow (and CTFE-able), so you should be able to write your assert as: assert(condition, format(x = %s, blahblah, x)); With the latest DMD from updated GIT head: import std.string: format; void main() pure nothrow { string x = hello; bool condition = true; assert(condition, format(x = %s, blahblah, x)); } It gives: test.d(5): Error: 'std.string.format!(char, string).format' is not nothrow test.d(2): Error: function 'D main' is nothrow yet may throw [...] Oops. Apparently I wrote nothrow but forgot to test it. I did test pure and @safe, though, so at least those two should work. format can't be nothrow, because it throws when you screw up the format specifiers. You have to wrap it in a try-catch block and assert(0) in the catch block if you want to put it in a nothrow function. std.datetime does this in at least a few places. - Jonathan M Davis
Re: Safety/purity and assert/enforce error messages
On Thu, Sep 12, 2013 at 04:07:24PM -0400, Jonathan M Davis wrote: On Thursday, September 12, 2013 12:42:34 H. S. Teoh wrote: On Thu, Sep 12, 2013 at 09:12:18PM +0200, bearophile wrote: H. S. Teoh: In phobos git HEAD, std.format has been made pure @safe nothrow (and CTFE-able), so you should be able to write your assert as: assert(condition, format(x = %s, blahblah, x)); With the latest DMD from updated GIT head: import std.string: format; void main() pure nothrow { string x = hello; bool condition = true; assert(condition, format(x = %s, blahblah, x)); } It gives: test.d(5): Error: 'std.string.format!(char, string).format' is not nothrow test.d(2): Error: function 'D main' is nothrow yet may throw [...] Oops. Apparently I wrote nothrow but forgot to test it. I did test pure and @safe, though, so at least those two should work. format can't be nothrow, because it throws when you screw up the format specifiers. You have to wrap it in a try-catch block and assert(0) in the catch block if you want to put it in a nothrow function. std.datetime does this in at least a few places. [...] Right. Makes me wanna suggest adding this template to std.exception: auto assumeWontThrow(alias fun, T...)(T args) nothrow { try { return fun(args); } catch(Exception) { // You broke your promise, I die. assert(0); } } Then you can write things like: int mayThrow(int arg) { if (arg 0) throw new Exception(...); return BBN(arg); } int iWontThrow() nothrow { // -- N.B. this function is nothrow static assert(123 0); return assumeWontThrow!mayThrow(123); } T -- It won't be covered in the book. The source code has to be useful for something, after all. -- Larry Wall
Re: Safety/purity and assert/enforce error messages
On Thursday, September 12, 2013 22:17:30 Joseph Rushton Wakeling wrote: On 12/09/13 22:07, Jonathan M Davis wrote: format can't be nothrow, because it throws when you screw up the format specifiers. You have to wrap it in a try-catch block and assert(0) in the catch block if you want to put it in a nothrow function. std.datetime does this in at least a few places. The annoyance of this is that it means that any otherwise @safe pure nothrow function that has an assert() in it can be blocked from being nothrow if it needs a formatted string for the assert failure message. Note that this restriction still applies even if the code is being compiled with -release and the assertion therefore stripped out. Or am I missing a trick as to how to deal with assert() and enforce() ... ? :-) You can put the try-catch in a version(assert) block to get around that problem, but it is true that it's not exactly ideal. However, there really isn't any way around that with a function that takes a format string unless you want it to ignore bad arguments. You'd need a function like text which just appends all of its arguments together in order to get around that problem. - Jonathan M Davis
Re: Safety/purity and assert/enforce error messages
On 12/09/13 22:07, Jonathan M Davis wrote: format can't be nothrow, because it throws when you screw up the format specifiers. You have to wrap it in a try-catch block and assert(0) in the catch block if you want to put it in a nothrow function. std.datetime does this in at least a few places. The annoyance of this is that it means that any otherwise @safe pure nothrow function that has an assert() in it can be blocked from being nothrow if it needs a formatted string for the assert failure message. Note that this restriction still applies even if the code is being compiled with -release and the assertion therefore stripped out. Or am I missing a trick as to how to deal with assert() and enforce() ... ? :-)
Re: Safety/purity and assert/enforce error messages
On 12/09/13 20:49, H. S. Teoh wrote: In phobos git HEAD, std.format has been made pure @safe nothrow (and CTFE-able), so you should be able to write your assert as: assert(condition, format(x = %s, blahblah, x)); Don't think it will work on 2.063.2, though, since it was a relatively recent change. I suspect this will only work starting from 2.064. Ahh, good to know, thanks. I guess I'll withhold tweaking such things until after the next release ... :-)
Re: Safety/purity and assert/enforce error messages
On Thu, Sep 12, 2013 at 08:13:37PM +0200, Joseph Rushton Wakeling wrote: Hi all, Suppose that I want to insert some variable values into an assert error message. The easy way to do this is something like: assert(someCondition, text(x = , x, , cannot blah blah blah)); However, the use of text() prevents me from applying @safe and other such attributes to the function containing this assert, even though text() will only be called in the event of an assertion failure. Is there any reliable way to include variable values in the error message that doesn't interfere with @safe, pure, etc.? Using to!string has a similar problem. [...] In phobos git HEAD, std.format has been made pure @safe nothrow (and CTFE-able), so you should be able to write your assert as: assert(condition, format(x = %s, blahblah, x)); Don't think it will work on 2.063.2, though, since it was a relatively recent change. I suspect this will only work starting from 2.064. T -- MASM = Mana Ada Sistem, Man!
Re: Safety/purity and assert/enforce error messages
On 12/09/13 22:23, Jonathan M Davis wrote: You can put the try-catch in a version(assert) block to get around that problem, but it is true that it's not exactly ideal. However, there really isn't any way around that with a function that takes a format string unless you want it to ignore bad arguments. You'd need a function like text which just appends all of its arguments together in order to get around that problem. Well, I have been using text() to generate my assert error messages, but the trouble is that (at least in 2.063) it's not @safe, pure or nothrow ... :-(
Re: Safety/purity and assert/enforce error messages
On Thu, Sep 12, 2013 at 11:37:10PM +0200, Joseph Rushton Wakeling wrote: On 12/09/13 22:23, Jonathan M Davis wrote: You can put the try-catch in a version(assert) block to get around that problem, but it is true that it's not exactly ideal. However, there really isn't any way around that with a function that takes a format string unless you want it to ignore bad arguments. You'd need a function like text which just appends all of its arguments together in order to get around that problem. Well, I have been using text() to generate my assert error messages, but the trouble is that (at least in 2.063) it's not @safe, pure or nothrow ... :-( Even in git HEAD, text() may still throw. So ultimately, you still need assumeWontThrow: https://github.com/D-Programming-Language/phobos/pull/1571 :) T -- Some days you win; most days you lose.
Re: Safety/purity and assert/enforce error messages
On Thursday, 12 September 2013 at 20:07:40 UTC, Jonathan M Davis wrote: On Thursday, September 12, 2013 12:42:34 H. S. Teoh wrote: On Thu, Sep 12, 2013 at 09:12:18PM +0200, bearophile wrote: H. S. Teoh: In phobos git HEAD, std.format has been made pure @safe nothrow (and CTFE-able), so you should be able to write your assert as: assert(condition, format(x = %s, blahblah, x)); With the latest DMD from updated GIT head: import std.string: format; void main() pure nothrow { string x = hello; bool condition = true; assert(condition, format(x = %s, blahblah, x)); } It gives: test.d(5): Error: 'std.string.format!(char, string).format' is not nothrow test.d(2): Error: function 'D main' is nothrow yet may throw [...] Oops. Apparently I wrote nothrow but forgot to test it. I did test pure and @safe, though, so at least those two should work. format can't be nothrow, because it throws when you screw up the format specifiers. You have to wrap it in a try-catch block and assert(0) in the catch block if you want to put it in a nothrow function. std.datetime does this in at least a few places. - Jonathan M Davis Why don't we have a format function that is statically checked?
Re: Safety/purity and assert/enforce error messages
On Thu, Sep 12, 2013 at 11:45:07PM +0200, Meta wrote: On Thursday, 12 September 2013 at 20:07:40 UTC, Jonathan M Davis wrote: [...] format can't be nothrow, because it throws when you screw up the format specifiers. You have to wrap it in a try-catch block and assert(0) in the catch block if you want to put it in a nothrow function. std.datetime does this in at least a few places. - Jonathan M Davis Why don't we have a format function that is statically checked? Currently, this is not possible, because the format string may be a runtime-computed value. For example: void main(string[] args) { // fmtString is only known at runtime. auto fmtString = File(fmtstrings.cfg).byLine().front.idup; // This will throw if command-line arguments don't match // format string. writefln(fmtString, args[1..$]); } It *is* true, however, that the vast majority of format usage uses a static format string. In those cases, it *would* be nice to have a nothrow variant of format(). Arguably, we could have this variant of format: string staticFormat(string fmt, T...)(T args) { ... } which takes a compile-time format string. Then it can be statically verified to be pure, @safe, nothrow, etc.. This is actually more tricky than it sounds, though. Specifiers like %s are parsed into Format!char objects, which may be passed to a user-defined type's toString method, so the nothrow-ness of staticFormat() may change depending on whether the user-defined toString throws. T -- Старый друг лучше новых двух.
Re: Safety/purity and assert/enforce error messages
On Thursday, 12 September 2013 at 22:04:20 UTC, H. S. Teoh wrote: Currently, this is not possible, because the format string may be a runtime-computed value. For example: ... When you don't have a runtime computed format string, though (which is generally the case for my code, at least), it would be extremely useful for a literal format string to be statically verified and nothrow. One really nice thing I've seen with the Rust language is that they have a fmt macro that statically verifies that the types of its arguments match the format string. It *is* true, however, that the vast majority of format usage uses a static format string. In those cases, it *would* be nice to have a nothrow variant of format(). Arguably, we could have this variant of format: string staticFormat(string fmt, T...)(T args) { ... } which takes a compile-time format string. Then it can be statically verified to be pure, @safe, nothrow, etc.. This is actually more tricky than it sounds, though. Specifiers like %s are parsed into Format!char objects, which may be passed to a user-defined type's toString method, so the nothrow-ness of staticFormat() may change depending on whether the user-defined toString throws. Is it necessary to allow toString to throw? I can't think of any reason other than the object being in an invalid state, in which case maybe it should throw an Error.