enforce()?

Sean Kelly sean at invisibleduck.org
Mon Jun 21 11:14:54 PDT 2010


Andrei Alexandrescu Wrote:

> On 06/20/2010 06:18 PM, Vladimir Panteleev wrote:
> > On Mon, 21 Jun 2010 00:17:28 +0300, Walter Bright
> > <newshound2 at digitalmars.com> wrote:
> >
> >> An input to a dll is user input, and should be validated (for the sake
> >> of security, and other reasons). Validating it is not debugging.
> >
> > I don't understand why you're saying this. Security checks in DLL
> > functions are pointless, for the reasons I already outlined:
> [snip]
> 
> I think the matter is simpler than that. Essentially DbC is modular 
> integrity checking. If Phobos enforce()s parameters in calls, then it 
> considers its own integrity a different matter than the integrity of the 
> application it's used with.
> 
> If Phobos used contracts to validate parameters, it would directly share 
> responsibility for the integrity of the entire application. That way, 
> users will not be sure whether the failure is a bug in Phobos or one in 
> their own code.

If a unrecoverable failure occurs within the process, does it matter where the error originated?

I've been thinking about this a bit and am starting to wonder about the benefit of distinguishing API boundary integrity checking vs. internal integrity checking.  First, what if a library eats its own dogfood?  If my library provides a public method to spawn threads and the library itself uses threads internally then I have two different methods of checking the integrity of my own library, each possibly throwing different exceptions (enforce throws Exception while assert throws AssertError).  At the very least, this seems like it could cause maintenance issues because a logic change deep within the library may require additional exception handling to deal with what are intended to be user-facing errors.

In a similar vein, if contracts are used within an API but a different mode of checking is used at the API boundary, when contracts are enabled in that API the user is faced with the bizarre issue of receiving AssertErrors from internal API logic errors but only Exceptions from his own logic errors for API boundary calls.  When you say that DbC is modular I'd presume that means it's encapsulated within each distinct subsystem, but it seems like this isn't true at all.  The alternative is to turn DbC off in the library and either live with undefined behavior or a hard crash if there's a bug in the library, a circumstance which is again forced upon the user.

Regarding DbC, I can't say that I've ever worked on a system where lives hung in the balance (an admittedly extreme example of where DbC is useful), but if I were sufficiently concerned about process integrity that I had contracts enabled then I don't think I would trust that a third-party library was bug-free and therefore didn't need its own contract checking in place.  Once I've accepted the cost of integrity checking I want it everywhere, not just in my own code.  It makes for consistent error checking behavior (I'd assume there is a system in place to trap DbC errors specifically) and provides full-process integrity checking.

I think the only boundary that really matters is the process boundary.  Any error within a process has the same effect regardless of whether it's in user code or library code--corrupted memory, segfaults, etc--so why make a distinction between code I wrote and code someone else wrote?  By the same token, if the user chooses to disable contracts then why force them upon him for some errors but not others?  The user is making the explicit choice to run his process through a meat-grinder if something unexpected happens, he's effectively asserting that his code is perfect, so why tell him that "no, it's actually not."

For me, the more difficult issue is how much integrity checking should be done.  For example, I created an AVL tree a while back that verified that the tree was still properly balanced after every API call.  This was great from a code verification standpoint, but the check completely violated the complexity guarantees and ultimately checked something that could have been proven to a reasonable degree of confidence through code reviews and unit testing.  Should checks like this be enabled automatically when DbC is turned on?  Should there be different levels of DbC?  In some respects I feel like there's a difference between in/out contracts and invariants, but even that doesn't seem completely right.  Thoughts?


More information about the Digitalmars-d mailing list