assert(expression, error)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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