www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: Against enforce()

reply bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 No need to blow out of proportion everything that serves a point.

You are right, but probably I am doing that because I see you nearly deaf to the problems I see in Phobos usages of enforce().
 There are only few places in which use of enforce (or checking in general) 
 slows things down.

I have hit some of such cases in my code, finding them through profiling. At first I didn't expect Phobos functions to give those problems :-(
 Because I don't condone defining large exception hierarchies.

The WrongArgumentException I am talking about comes from a set of less than about ten most useful exceptions, and I mean this hierarchy to be flat, all of them come from Exception. So this is not a large exception hierarchy.
 but that's not an issue that is the charter of enforce or that 
 enforce prevents.

When you design a language and its standard library you have to keep a balance between making things very easy but not good enough, and very hard/fussy but better (see the simplicity of ddoc and D unittests, ddoc is mostly OK, but unnittests are probably a bit too much simple, they miss some essential features like a name). In my opinion a standard library is meant to throw a bit better exceptions than fully generic ones.
 It makes the standard library writers productive.

enforce() has clearly some disadvantages. I believe the very small convenience it brings to Phobos writers is not enough to justify its usage in many cases. One of such cases is inside iota(), where I suggest to replace its usage with a if+throw to allow iota() to be usable in pure functions too.
 Hoping less and doing more would be great.

You are right. I am sorry. I am trying to help, even if I am not doing enough. Bye and thank you for your answers, bearophile
Mar 16 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 03/16/2011 09:33 PM, bearophile wrote:
 Andrei:

 No need to blow out of proportion everything that serves a point.

You are right, but probably I am doing that because I see you nearly deaf to the problems I see in Phobos usages of enforce().

It's not about me. Phobos has several contributors (including non-committers) who could be receptive to such issues and proactive about fixing them either in the language or the library.
 There are only few places in which use of enforce (or checking in
 general) slows things down.

I have hit some of such cases in my code, finding them through profiling. At first I didn't expect Phobos functions to give those problems :-(

There are indeed a few places in which using enforce makes things slower. The principled approach to such things is not to blame enforce, but to fix the compiler to allow such a simple and effective idiom.
 Because I don't condone defining large exception hierarchies.

The WrongArgumentException I am talking about comes from a set of less than about ten most useful exceptions, and I mean this hierarchy to be flat, all of them come from Exception. So this is not a large exception hierarchy.

You may want to add a DIP at http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel (possibly backed up by a pull request) and discuss it here. There are always ten "most useful" exceptions, except not all people think of the same ten.
 but that's not an issue that is the charter of enforce or that
 enforce prevents.

When you design a language and its standard library you have to keep a balance between making things very easy but not good enough, and very hard/fussy but better (see the simplicity of ddoc and D unittests, ddoc is mostly OK, but unnittests are probably a bit too much simple, they miss some essential features like a name). In my opinion a standard library is meant to throw a bit better exceptions than fully generic ones.

The rhetoric sounds great. Now let's see a concrete proposal.
 It makes the standard library writers productive.

enforce() has clearly some disadvantages. I believe the very small convenience it brings to Phobos writers is not enough to justify its usage in many cases.

enforce is convenient and leads to short, simple, and correct functions. Small and large teams have used and are using similar artifacts in codebases at three other companies I worked and work for. On what basis are you assessing the amount of convenience it brings?
 One of such cases is inside iota(), where I suggest to replace its
 usage with a if+throw to allow iota() to be usable in pure functions
 too.

I'd almost suggest using bugzilla.
 Hoping less and doing more would be great.

You are right. I am sorry. I am trying to help, even if I am not doing enough.

If anything please don't go again the sheepish route. If you were really sorry you wouldn't have started with something to be sorry about - and in what tone - in the first place. After the initial self-righteous and over-confident stance, it always seems awkwardly insincere. Wouldn't a simple and honest discussion be best? Framing everything as a diatribe against a two-line function is just ungainly. Andrei
Mar 16 2011
next sibling parent reply Daniel Gibson <metalcaedes gmail.com> writes:
I'd just like to summarize what useful stuff came out of this topic:

* enforce is useful and more than a "always activated assert" ;-)
* enforce prevents inlining and thus has negative impact on performance - this
should probably be fixed.
* enforce can't be used in weakly pure functions - this has the side-effect that
iota() (maybe other functions as well) can't be used in pure functions  - this
should also be fixed. if fixing it is difficult /maybe/ if+throw should be used
in potentially (weakly) pure functions in phobos until it is fixed
* enforce's docs should probably mention null and false as well (even though
maybe "zero" implies that, but it'd be clearer)
  - while I'm at it: I think the enforceEx signature in the docs is incomplete

* it *may* encourage using the generic Exception instead of a specific more
meaningful exception
  - related: some places in phobos could use a more specific Exception, e.g.
iota()

Cheers,
- Daniel
Mar 16 2011
next sibling parent reply Don <nospam nospam.com> writes:
Daniel Gibson wrote:
 I'd just like to summarize what useful stuff came out of this topic:
 
 * enforce is useful and more than a "always activated assert" ;-)
 * enforce prevents inlining and thus has negative impact on performance - this
 should probably be fixed.
 * enforce can't be used in weakly pure functions - this has the side-effect
that
 iota() (maybe other functions as well) can't be used in pure functions  - this
 should also be fixed. if fixing it is difficult /maybe/ if+throw should be used
 in potentially (weakly) pure functions in phobos until it is fixed

That was discussed on the Phobos ng some time back. I don't think it's a compiler issue. It's just not pure because the lazy delegate isn't marked as pure. Since you can overload on pure, I'm not sure why this hasn't been done yet.
 * enforce's docs should probably mention null and false as well (even though
 maybe "zero" implies that, but it'd be clearer)
   - while I'm at it: I think the enforceEx signature in the docs is incomplete
 
 * it *may* encourage using the generic Exception instead of a specific more
 meaningful exception
   - related: some places in phobos could use a more specific Exception, e.g.
iota()
 
 Cheers,
 - Daniel

Mar 16 2011
parent reply Don <nospam nospam.com> writes:
Lars T. Kyllingstad wrote:
 On Thu, 17 Mar 2011 07:51:33 +0100, Don wrote:
 
 Daniel Gibson wrote:
 I'd just like to summarize what useful stuff came out of this topic:

 * enforce is useful and more than a "always activated assert" ;-) *
 enforce prevents inlining and thus has negative impact on performance -
 this should probably be fixed.
 * enforce can't be used in weakly pure functions - this has the
 side-effect that iota() (maybe other functions as well) can't be used
 in pure functions  - this should also be fixed. if fixing it is
 difficult /maybe/ if+throw should be used in potentially (weakly) pure
 functions in phobos until it is fixed

compiler issue. It's just not pure because the lazy delegate isn't marked as pure. Since you can overload on pure, I'm not sure why this hasn't been done yet.

You can overload on pure, yes, but only when you pass an explicit delegate. The following doesn't work, for instance: void foo(pure lazy string s) { ... } The compiler complains that "basic type expected, not pure".

Ah, OK. I was pretty sure there wasn't a problem with delegates, didn't realize that lazy was the issue. Nonetheless, I think we can just overload enforce() to fix this problem.
 With "lazy", the compiler creates a delegate under the hood, and it needs 
 the ability to deduce when that delegate can be marked as pure.  For the 
 function above, for instance, passing a simple string literal should be 
 perfectly fine, as should the following:
 
   int baz() pure { ... }
   string bar(int i) pure { ... }
 
   foo(bar(baz()));
 
 -Lars

Mar 17 2011
parent bearophile <bearophileHUGS lycos.com> writes:
Don:

 Ah, OK. I was pretty sure there wasn't a problem with delegates, didn't 
 realize that lazy was the issue. Nonetheless, I think we can just 
 overload enforce() to fix this problem.

In one of the answers I've written to Andrei I have shown this link, it shows the problem is caused by lazy: http://d.puremagic.com/issues/show_bug.cgi?id=5746 What is the enforce() overload do you suggest to add to Phobos? Bye, bearophile
Mar 17 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday 16 March 2011 23:51:33 Don wrote:
 Daniel Gibson wrote:
 I'd just like to summarize what useful stuff came out of this topic:
 
 * enforce is useful and more than a "always activated assert" ;-)
 * enforce prevents inlining and thus has negative impact on performance -
 this should probably be fixed.
 * enforce can't be used in weakly pure functions - this has the
 side-effect that iota() (maybe other functions as well) can't be used in
 pure functions  - this should also be fixed. if fixing it is difficult
 /maybe/ if+throw should be used in potentially (weakly) pure functions
 in phobos until it is fixed

That was discussed on the Phobos ng some time back. I don't think it's a compiler issue. It's just not pure because the lazy delegate isn't marked as pure. Since you can overload on pure, I'm not sure why this hasn't been done yet.

Probably because 1. Very little has been done with pure in Phobos thus far in general. 2. How many people know that you can overload on pure? _I_ sure didn't know that. How does that even work? The pure version is called if the caller is pure? Or are you talking about overloading on the lazy delegate? How would that be determined to be pure anyway? If the expression is pure? The fact that format isn't pure will rain on that parade a fair bit, but there _are_ quite a few uses of enforce (probably even the majority) which are just string literals, so that would go a fair ways. Overall, I think that the biggest obstacle to pure at this point is the lack of conditional purity for templates. We need to be able to say that a templated function is pure if it meets some set of conditions (like every function that it calls is pure). I believe that the best proposal for syntax on that is to do pure(condition) instead of just pure. Of course, nothrow, safe, trusted, etc. would likely need to have the same. But regardless, the fact that you can't generally make templated functions pure (especially in std.range and std.algorithm) _really_ puts a kink in using purity. I _was_ able to use pure fairly heavily in std.datetime, but it's probably just about the only place in Phobos right now that use pure much. - Jonathan M Davis
Mar 17 2011
prev sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Thu, 17 Mar 2011 07:51:33 +0100, Don wrote:

 Daniel Gibson wrote:
 I'd just like to summarize what useful stuff came out of this topic:
 
 * enforce is useful and more than a "always activated assert" ;-) *
 enforce prevents inlining and thus has negative impact on performance -
 this should probably be fixed.
 * enforce can't be used in weakly pure functions - this has the
 side-effect that iota() (maybe other functions as well) can't be used
 in pure functions  - this should also be fixed. if fixing it is
 difficult /maybe/ if+throw should be used in potentially (weakly) pure
 functions in phobos until it is fixed

That was discussed on the Phobos ng some time back. I don't think it's a compiler issue. It's just not pure because the lazy delegate isn't marked as pure. Since you can overload on pure, I'm not sure why this hasn't been done yet.

You can overload on pure, yes, but only when you pass an explicit delegate. The following doesn't work, for instance: void foo(pure lazy string s) { ... } The compiler complains that "basic type expected, not pure". With "lazy", the compiler creates a delegate under the hood, and it needs the ability to deduce when that delegate can be marked as pure. For the function above, for instance, passing a simple string literal should be perfectly fine, as should the following: int baz() pure { ... } string bar(int i) pure { ... } foo(bar(baz())); -Lars
Mar 17 2011
prev sibling parent Kagamin <spam here.lot> writes:
bearophile Wrote:

 When you design a language and its standard library you have to keep a balance
between making things very easy but not good enough, and very hard/fussy but
better (see the simplicity of ddoc and D unittests, ddoc is mostly OK, but
unnittests are probably a bit too much simple, they miss some essential
features like a name). In my opinion a standard library is meant to throw a bit
better exceptions than fully generic ones.
 

.net framework was designed to use sizeable exception hierarchy, though this approach failed, in most cases everything goes ok and in the case of an error you can't recover, no matter what error it is. So the code usually ends up either catching Exception or not catching anything.
Mar 17 2011