Re: Safety/purity and assert/enforce error messages

2013-09-12 Thread H. S. Teoh
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

2013-09-12 Thread Jonathan M Davis
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

2013-09-12 Thread H. S. Teoh
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

2013-09-12 Thread bearophile

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

2013-09-12 Thread Jonathan M Davis
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

2013-09-12 Thread H. S. Teoh
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

2013-09-12 Thread Jonathan M Davis
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

2013-09-12 Thread Joseph Rushton Wakeling

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

2013-09-12 Thread Joseph Rushton Wakeling

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

2013-09-12 Thread H. S. Teoh
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

2013-09-12 Thread Joseph Rushton Wakeling

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

2013-09-12 Thread H. S. Teoh
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

2013-09-12 Thread Meta
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

2013-09-12 Thread H. S. Teoh
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

2013-09-12 Thread Meta

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.