assert(expression, error)

2011-02-12 Thread spir

Hello,

Is there a way to specify what error to throw using (a variant of) assert:
assert(n  0, new ValueError(...));

(Sure, one can write:
if (n = 0)
throw new ValueError(...));
but the same remark applies to plain assert: the whole point of assert is to 
have it as builtin feature with clear application field  well-known semantics, 
shared by the community of D programmers.)


Denis
--
_
vita es estrany
spir.wikidot.com



Re: assert(expression, error)

2011-02-12 Thread Jonathan M Davis
On Saturday 12 February 2011 05:23:06 spir wrote:
 Hello,
 
 Is there a way to specify what error to throw using (a variant of) assert:
  assert(n  0, new ValueError(...));
 
 (Sure, one can write:
  if (n = 0)
  throw new ValueError(...));
 but the same remark applies to plain assert: the whole point of assert is
 to have it as builtin feature with clear application field  well-known
 semantics, shared by the community of D programmers.)

You mean std.exception.enforce?

assert throws AssertError. Regardless, you probably shouldn't be creating new 
Error types generally. You're _not_ supposed to catch errors and try and handle 
them, so there really isn't any benefit in creating new Error types generally 
anyway. If you want to assert, use assert. Let it be AssertError.

If you want to throw a specific Exception type, and you want it to be a one-
liner, use enforce. Be aware, however, that enforce is lazy, so any function 
which uses it can't currently be inlined.

- Jonathan M Davis


Re: assert(expression, error)

2011-02-12 Thread Tomek Sowiński
spir napisał:

 Is there a way to specify what error to throw using (a variant of) assert:
  assert(n  0, new ValueError(...));
 
 (Sure, one can write:
  if (n = 0)
  throw new ValueError(...));
 but the same remark applies to plain assert: the whole point of assert is to 
 have it as builtin feature with clear application field  well-known 
 semantics, 
 shared by the community of D programmers.)

With built-in assert, no. But std.exception can do it.

enforce(n  0, new ValueError(...));

-- 
Tomek



Re: assert(expression, error)

2011-02-12 Thread Andrej Mitrovic
Yeah, enforce is great. Here's one way I use it for external libraries
in one of my projects:

class sndfileException : Exception
{
this(SNDFILE *sndfile)
{
super(to!string(sf_strerror(sndfile)));
}
}

auto handle = sf_open(args);  // on failure returns null
enforce(handle !is null, new libsndException());

The sf_strerror function is from a library function that returns a C
string with the last error that occurred for a specific handle
(SNDFILE*). So I just made a simple exception wrapper for it in the
libsndException class.


Re: assert(expression, error)

2011-02-12 Thread bearophile
Andrej Mitrovic:

 Yeah, enforce is great.

Enforce is not disabled in release mode. Currently a function with enforce 
inside can't be nothrow, and it can't be inlined.

Bye,
bearophile


Re: assert(expression, error)

2011-02-12 Thread Andrej Mitrovic
On 2/12/11, bearophile bearophileh...@lycos.com wrote:
 Andrej Mitrovic:

 Yeah, enforce is great.

 Enforce is not disabled in release mode.

Right. That's why I need it in this case, since the library can return
null at runtime due to user or even (audio) hardware errors.

 Currently a function with enforce
 inside can't be nothrow, and it can't be inlined.

 Bye,
 bearophile


Of course it can't be nothrow? I thought the idea of enforce is to
throw a custom exception when needed, so how can you expect a function
which throws an exception to be nothrow?

Btw, is the inline problem just a DMD implementation problem, or does
enforce have to be fixed for that?


Re: assert(expression, error)

2011-02-12 Thread Jonathan M Davis
On Saturday 12 February 2011 06:54:01 bearophile wrote:
 Andrej Mitrovic:
  Yeah, enforce is great.
 
 Enforce is not disabled in release mode. Currently a function with enforce
 inside can't be nothrow, and it can't be inlined.

Yeah. Well it makes no sense whatsover for a function with enforce to be 
nothrow. The whole _point_ is to throw an exception, and enforce had better not 
be disabled for release. It throws an _Exception_ not an AssertError. It's not 
_supposed_ to be used for stuff which isn't tested in release. That's what 
assert 
is for.

Now, the fact that it can't be inlined is a problem, but the rest of it is how 
it's _supposed_ to work.

- Jonathan M Davis


Re: assert(expression, error)

2011-02-12 Thread Michel Fortin
On 2011-02-12 10:05:34 -0500, Andrej Mitrovic 
andrej.mitrov...@gmail.com said:



Btw, is the inline problem just a DMD implementation problem, or does
enforce have to be fixed for that?


DMD implementation problem. The inliner doesn't support ref, out, lazy, 
and delegate arguments at this time. Enforce uses a lazy second 
argument so it doesn't get inlined.


--
Michel Fortin
michel.for...@michelf.com
http://michelf.com/



Re: assert(expression, error)

2011-02-12 Thread Jonathan M Davis
On Saturday 12 February 2011 07:05:34 Andrej Mitrovic wrote:
 On 2/12/11, bearophile bearophileh...@lycos.com wrote:
  Andrej Mitrovic:
  Yeah, enforce is great.
  
  Enforce is not disabled in release mode.
 
 Right. That's why I need it in this case, since the library can return
 null at runtime due to user or even (audio) hardware errors.
 
  Currently a function with enforce
  inside can't be nothrow, and it can't be inlined.
  
  Bye,
  bearophile
 
 Of course it can't be nothrow? I thought the idea of enforce is to
 throw a custom exception when needed, so how can you expect a function
 which throws an exception to be nothrow?
 
 Btw, is the inline problem just a DMD implementation problem, or does
 enforce have to be fixed for that?

It's because the second argument to enforce is lazy. Whether dmd will ever be 
able to reasonably inline functions which take lazy arguments, I don't know 
(there's a fair bit that goes on underneath to make lazy happen, so the 
resulting code isn't exactly short). However, it has been discussed from time 
to 
time to have a non-lazy version of enforce. That would require either creating 
another function (e.g. enforceNonLazy) or making dmd smart enough to be able to 
have two versions of a function - one lazy and one non-lazy - and have it use 
the non-lazy one when it can (e.g. when it's only given a string and there's 
nothing which the resulting delegate would do other than return the string - 
making it non-lazy in such a case does nothing).

Regardless, it's why I pretty much never use lazy. I don't think that

if(condition)
throw new Exception(my message);

is onerous at all, and I don't want to worry about the inlining issue. But if 
your function isn't likely to be inlined anyway, or for some reason, you just 
don't like having the if statement, then enforce is just fine.

- Jonathan M Davis


Re: assert(expression, error)

2011-02-12 Thread Andrej Mitrovic
On 2/12/11, Jonathan M Davis jmdavisp...@gmx.com wrote:
 But
 if
 your function isn't likely to be inlined anyway, or for some reason, you
 just
 don't like having the if statement, then enforce is just fine.

 - Jonathan M Davis


It's noticeable in code and partially self-documenting, that's why I
use it. I could go with
if (exp) throw new exc();

Same deal, I guess.

As for inlining, I really have yet to push D to it's limits to see
that as a problem.


Re: assert(expression, error)

2011-02-12 Thread bearophile
Andrej Mitrovic:

 Right. That's why I need it in this case, since the library can return
 null at runtime due to user or even (audio) hardware errors.

So in your case enforce is OK.
(In general, I suggest to use D design by contract a lot (with asserts)).

Bye,
bearophile


Re: assert(expression, error)

2011-02-12 Thread Jonathan M Davis
On Saturday 12 February 2011 08:05:15 Andrej Mitrovic wrote:
 On 2/12/11, Jonathan M Davis jmdavisp...@gmx.com wrote:
  But
  if
  your function isn't likely to be inlined anyway, or for some reason, you
  just
  don't like having the if statement, then enforce is just fine.
  
  - Jonathan M Davis
 
 It's noticeable in code and partially self-documenting, that's why I
 use it. I could go with
 if (exp) throw new exc();
 
 Same deal, I guess.
 
 As for inlining, I really have yet to push D to it's limits to see
 that as a problem.

I have a major problem with functions which are _obviously_ inlineable not 
being 
inlineable just because of using enforce. For instance, take the function on 
std.datetime.TimeOfDay which is used to set the hour. I could write it as

@property void hour(int hour) pure
{
enforce(hour = 0  hour  24,
 new DateTimeException(numToString(hour) ~  is not a valid 
hour of the day.));

_hour = cast(ubyte)hour;
}

or I could write it

@property void hour(int hour) pure
{
if(hour  0 || hour = 24)
throw new DateTimeException(numToString(hour) ~  is not a valid 
hour of the day.));

_hour = cast(ubyte)hour;
}

Aside from enforce, this function is a one-liner. It's obvious that it should 
be 
inlined and that it _would_ be inlined if enforce isn't used. But if I were to 
use enforce, it couldn't be inlined. It's situations like that which really 
bother me. enforce is definitely and obviously harming code efficiency in such 
a 
case.

Now, what happened a lot of the time in std.datetime is that I ended up with a 
helper function with did something similar to enforce (simply because the same 
sort of thing had to be enforced in multiple places, so a helper function made 
a 
lot of sense), and I didn't make that helper function lazy. For instance, the 
actual definition for the hour property is

@property void hour(int hour) pure
{
enforceValid!hours(hour);
_hour = cast(ubyte)hour;
}

After all the template fun is sorted out, the enforceValid line should become 
something like

if(!(hour = 0  hour = TimeOfDay.maxHour))
throw new DateTimeException(numToString(hour) ~  is not a valid 
hour of the day., file, line);

That should be totally inlineable _and_ it has the advantage of not making you 
use an if statement if you want to avoid that. But I'm increasingly finding 
that 
that is a pattern in my code. I need to validate something multiple times 
throughout my code, and I want it to result in the same exception each time. 
So, 
I create a helper function which does the test and then throws if it fails. And 
often, I create a separate function which does the test and returns the result 
(making the helper enforce-like function call that function). That way, I can 
use the same test in assertions and the like if need be.

So, if you're testing the same thing in multiple places, you'll probably want 
to 
write your own helper function anyway, completely obviating enforce. The 
overall 
result is that I rarely use enforce.

- Jonathan M Davis


Re: assert(expression, error)

2011-02-12 Thread spir

On 02/12/2011 05:27 PM, Jonathan M Davis wrote:

Aside from enforce, this function is a one-liner. It's obvious that it should be
inlined and that it _would_ be inlined if enforce isn't used. But if I were to
use enforce, it couldn't be inlined. It's situations like that which really
bother me. enforce is definitely and obviously harming code efficiency in such a
case.


Hello again Jonathan,

Maybe a good use case of what I asked for in another thread: feedback from the 
compiler about whather a given func is inlinable. Imagine I don't know enforce 
is problematic. After all, at first sight, I can see no obvious reason (maybe 
from lack of knowledge). Then, how can one know? Could happily let it 
externalisable persuaded it would /for sure/ be inlined.
In your case, tough, I think it's not problematic since there are few chances 
for the func to represent a significant proportion of run time (I guess ;-). In 
my case, it a func called by a parser's Node constructor! Typically a major 
part of a parser's runtime is, precisely, generating millions on Nodes every 
second...


Denis
--
_
vita es estrany
spir.wikidot.com



Re: assert(expression, error)

2011-02-12 Thread Jonathan M Davis
On Saturday 12 February 2011 08:38:45 spir wrote:
 On 02/12/2011 05:27 PM, Jonathan M Davis wrote:
  Aside from enforce, this function is a one-liner. It's obvious that it
  should be inlined and that it _would_ be inlined if enforce isn't used.
  But if I were to use enforce, it couldn't be inlined. It's situations
  like that which really bother me. enforce is definitely and obviously
  harming code efficiency in such a case.
 
 Hello again Jonathan,
 
 Maybe a good use case of what I asked for in another thread: feedback from
 the compiler about whather a given func is inlinable. Imagine I don't know
 enforce is problematic. After all, at first sight, I can see no obvious
 reason (maybe from lack of knowledge). Then, how can one know? Could
 happily let it externalisable persuaded it would /for sure/ be inlined.
 In your case, tough, I think it's not problematic since there are few
 chances for the func to represent a significant proportion of run time (I
 guess ;-). In my case, it a func called by a parser's Node constructor!
 Typically a major part of a parser's runtime is, precisely, generating
 millions on Nodes every second...

There are tons of functions out there which are one or two lines long which 
should be inlined. Setter property functions and constructors are often good 
examples (though constructors do tend be a bit longer than one or two lines). 
Whether they're used often is certainly relevant (and the situation is 
obviously 
far worse if the _need_ to be inlined and aren't), but they should be inlined 
regardless. As long as the inliner is smart, however, it shouldn't be a 
problem. 
The problem here is an issue with how the current inliner works. It doesn't and 
shouldn't require a language change in the sense that you'd force inlining or 
whatnot. What it needs is for the inliner to be improved.

And while the example I gave may or may not actually result in being a 
performance problem for someone, I definitely can't assume that it won't be. 
It's 
in the standard library after all, and who knows what people are going to use 
it 
for. But I wasn't really trying to single out anything about std.datetime with 
that example. It's just that it was an easy example to give, since I already 
had 
the code. The issue is that using enforce in what should be a one line function 
(without the enforce) suddenly makes the function un-inlineable when you add 
the 
enforce call, and that _can_ seriously harm performance.

Regardless, the way this sort of problem is found if you're not already aware 
of 
lazy causing problems with inlining is that you profile your code. And if it 
shows that you're spending a lot of time in a particular function, you try and 
figure out how to make that function more efficient. Ultimately, that could 
mean 
looking at the assembly code, which _would_ tell you whether the function was 
inlined or not. I do agree that having to go so far as to look at the assembly 
code figure out whether a function is being inlined is not desirable, but I 
also 
don't think that you should _have_ to try and figure out whether a function is 
inlined. The compiler should be smart enough to deal with that. And it often 
is, 
but it also definitely has room for improvement. lazy parameters are a prime 
example of that.

- Jonathan M Davis