Jump to page: 1 2
Thread overview
Re: Safety/purity and assert/enforce error messages
Sep 12, 2013
H. S. Teoh
Sep 12, 2013
bearophile
Sep 12, 2013
H. S. Teoh
Sep 12, 2013
Jonathan M Davis
Sep 12, 2013
Meta
Sep 12, 2013
H. S. Teoh
Sep 13, 2013
Meta
Sep 12, 2013
H. S. Teoh
Sep 12, 2013
H. S. Teoh
Sep 12, 2013
Jonathan M Davis
Sep 12, 2013
Jonathan M Davis
Sep 12, 2013
H. S. Teoh
September 12, 2013
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!
September 12, 2013
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 ... :-)

September 12, 2013
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
September 12, 2013
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.
September 12, 2013
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
September 12, 2013
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() ... ? :-)

September 12, 2013
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
September 12, 2013
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
September 12, 2013
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.
September 12, 2013
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
« First   ‹ Prev
1 2