Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
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
|
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
On 02/12/2011 02:44 PM, Jonathan M Davis wrote: > 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. All right, thank you for this clear info, Jonathan. (Havn't used enforce yet, seems to be cool.) Denis -- _________________ vita es estrany spir.wikidot.com |
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
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. |
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | 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
|
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 2/12/11, bearophile <bearophileHUGS@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? |
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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
|
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
On Saturday 12 February 2011 07:05:34 Andrej Mitrovic wrote:
> On 2/12/11, bearophile <bearophileHUGS@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
|
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
On 2/12/11, Jonathan M Davis <jmdavisProg@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.
|
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | 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
|
February 12, 2011 Re: assert(expression, error) | ||||
---|---|---|---|---|
| ||||
On Saturday 12 February 2011 08:05:15 Andrej Mitrovic wrote: > On 2/12/11, Jonathan M Davis <jmdavisProg@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 |
Copyright © 1999-2021 by the D Language Foundation