Jump to page: 1 2 3
Thread overview
Feature request - isolated "in" contracts
Aug 26, 2004
Arcane Jill
Aug 26, 2004
Russ Lewis
Re: Feature request - isolated
Aug 26, 2004
Charlie
Aug 26, 2004
Arcane Jill
Aug 26, 2004
Charlie
Aug 26, 2004
Andy Friesen
Aug 26, 2004
Andy Friesen
Re: Feature request - isolated
Aug 26, 2004
Sean Kelly
Aug 26, 2004
Walter
Re: Feature request - isolated
Aug 27, 2004
Arcane Jill
Aug 27, 2004
Walter
Re: Feature request - isolated
Aug 27, 2004
Arcane Jill
Aug 27, 2004
Walter
Aug 27, 2004
Stewart Gordon
Aug 28, 2004
Walter
Sep 01, 2004
Stewart Gordon
Aug 27, 2004
Russ Lewis
Aug 28, 2004
Walter
Aug 28, 2004
Andy Friesen
Aug 28, 2004
Russ Lewis
Aug 30, 2004
Norbert Nemec
August 26, 2004
I would very much like this to compile:

#    double squareRoot(double d)
#    in
#    {
#        assert(d >= 0);
#    };
#    // function body supplied in linked library

Until yesterday, this compiled, but incorrectly. Walter has now fixed this bug, but he's fixed it in such a way that it now won't compile at all.

The issue is this. A function's "in" contract is a precondition with which /callers/ are expected to comply. If they do not, the bug is in the callers' code, not in the function body. Now, if the function is in a commercial library, the creators of that library may wish to keep their source code to themselves - but they'd still want to expose the precondition.

Worse, the callers' code could still be at the debug stage, while the library code may be a release build - in which case, not only will the application developer not be made aware of the precondition, but it won't even be executed!

The resolution is that preconditions must always be executed by the caller, not the callee. That way, caller bugs caused by violating the contract will be found, as they should. And these means that it must be possible to expose an "in" contract without exposing the implementation.

Does that sound reasonable?

Arcane Jill


August 26, 2004
Arcane Jill wrote:
> I would very much like this to compile:
> 
> #    double squareRoot(double d)
> #    in
> #    {
> #        assert(d >= 0);
> #    };
> #    // function body supplied in linked library
> 
> Until yesterday, this compiled, but incorrectly. Walter has now fixed this bug,
> but he's fixed it in such a way that it now won't compile at all.
> 
> The issue is this. A function's "in" contract is a precondition with which
> /callers/ are expected to comply. If they do not, the bug is in the callers'
> code, not in the function body. Now, if the function is in a commercial library,
> the creators of that library may wish to keep their source code to themselves -
> but they'd still want to expose the precondition.
> 
> Worse, the callers' code could still be at the debug stage, while the library
> code may be a release build - in which case, not only will the application
> developer not be made aware of the precondition, but it won't even be executed!
> 
> The resolution is that preconditions must always be executed by the caller, not
> the callee. That way, caller bugs caused by violating the contract will be
> found, as they should. And these means that it must be possible to expose an
> "in" contract without exposing the implementation.

I agree, but I would further argue that isolated "out" contracts should be allowed as well:
* Explicitly documents what callers can expect from a library
* Ensures that if the library changes (i.e. a future version changes its contracts), those who call it will report errors (when the previous contract is violated)
* In the future, optimizing compilers will probably use "out" contracts to optimize code that runs after the function call.

August 26, 2004
Couldn't you just comment out the in statement ?  Or will that break the contracts ?

>Worse, the callers' code could still be at the debug stage, while the library code may be a release build - in which case, not only will the application developer not be made aware of the precondition, but it won't even be executed

I'm not sure what can be done about this, other than slap the developer.

>The resolution is that preconditions must always be executed by the caller, not the callee. That way, caller bugs caused by violating the contract will be found, as they should.

Ive lost you here, in what way is 'in' not behaving as you would like, or when does 'in' not catch the conditions ( besides in a release build ? ).  And how can you control who 'executes' the conditions ?

Charlie

In article <cgl5ni$hfb$1@digitaldaemon.com>, Arcane Jill says...
>
>
>I would very much like this to compile:
>
>#    double squareRoot(double d)
>#    in
>#    {
>#        assert(d >= 0);
>#    };
>#    // function body supplied in linked library
>
>Until yesterday, this compiled, but incorrectly. Walter has now fixed this bug, but he's fixed it in such a way that it now won't compile at all.
>
>The issue is this. A function's "in" contract is a precondition with which /callers/ are expected to comply. If they do not, the bug is in the callers' code, not in the function body. Now, if the function is in a commercial library, the creators of that library may wish to keep their source code to themselves - but they'd still want to expose the precondition.
>
>Worse, the callers' code could still be at the debug stage, while the library code may be a release build - in which case, not only will the application developer not be made aware of the precondition, but it won't even be executed!
>
>The resolution is that preconditions must always be executed by the caller, not the callee. That way, caller bugs caused by violating the contract will be found, as they should. And these means that it must be possible to expose an "in" contract without exposing the implementation.
>
>Does that sound reasonable?
>
>Arcane Jill
>
>


August 26, 2004
In article <cgl94t$j0i$1@digitaldaemon.com>, Charlie says...

>>The resolution is that preconditions must always be executed by the caller, not the callee. That way, caller bugs caused by violating the contract will be found, as they should.
>
>Ive lost you here, in what way is 'in' not behaving as you would like, or when does 'in' not catch the conditions ( besides in a release build ? ).  And how can you control who 'executes' the conditions ?

It would have to be done by the compiler. Currently, given the code:

#   // Caller
#   f(x);
#
#   // Callee
#   int f(uint n)
#   in { /*precondition*/ }
#   out(r) { /*postcondition*/ }
#   body { /*body*/ }

the compiler invisibly transforms it to:

#   // Caller
#   f(x);
#
#   // Callee
#   int f(uint n)
#   {
#       /*precondition*/
#       /*body*/
#       /*postcondition*/
#   }

I would prefer that it instead transform it to:

#   // Caller
#   /*precondition*/
#   f(x);
#
#   // Callee
#   int f(uint n)
#   {
#       /*body*/
#       /*postcondition*/
#   }

See what I mean?

Arcane Jill


August 26, 2004
Arcane Jill wrote:
> I would very much like this to compile:
> 
> #    double squareRoot(double d)
> #    in
> #    {
> #        assert(d >= 0);
> #    };
> #    // function body supplied in linked library
> 
> Until yesterday, this compiled, but incorrectly. Walter has now fixed this bug,
> but he's fixed it in such a way that it now won't compile at all.
> 
> The issue is this. A function's "in" contract is a precondition with which
> /callers/ are expected to comply. If they do not, the bug is in the callers'
> code, not in the function body. Now, if the function is in a commercial library,
> the creators of that library may wish to keep their source code to themselves -
> but they'd still want to expose the precondition.
> 
> Worse, the callers' code could still be at the debug stage, while the library
> code may be a release build - in which case, not only will the application
> developer not be made aware of the precondition, but it won't even be executed!
> 
> The resolution is that preconditions must always be executed by the caller, not
> the callee. That way, caller bugs caused by violating the contract will be
> found, as they should. And these means that it must be possible to expose an
> "in" contract without exposing the implementation.
> 
> Does that sound reasonable?

Very!

This also opens the doorway to finally implementing contract inheritance without having to store things in the vtbl.

The first thing that came to mind is that contracts on classes accessed through an interface still need to test those contracts, even though which exact contracts are to be tested isn't even known at compile-time.  If the caller was responsible for testing contracts, this would be impossible.

However, this is completely counter to the spirit of both DbC and interfaces.  The contract is part of the interface, not the implementation.  Logically, then, interfaces need to be able to specify contracts, and methods implementing an interface must be /forbidden/ from specifying contracts of their own. (ditto for abstract classes/methods)

This could potentially cause some minor problems with mix-in styled interface implementation, though:

    interface IFace {
        // contracts allowed, but no body
        void hello() in { ... } out { ... };
        void goodbye() in { ... };
    }

    class PartialImpl {
        void hello()
        in { ... }
        out { ... }
        body { ... }
    }

    class FullImpl : PartialImpl, IFace {
        void goodbye() { // no contracts allowed here
            ...
        }

        /*
         * bam.  PartialImpl.hello has its own contracts, and therefore
         * does not satisfy IFace (unless the two happened to be
         * identical, but let's not go there)
         *
         * Because of this, an alias won't do.
         */
        void hello() {
            super.hello();
        }
    }

In this manner, all contracts are known at compile time, can therefore be checked by the caller and not the callee, contracts and interfaces conform more closely to their intended purposes, and we even keep link compatibility between debug and release builds.

 -- Captain Sidetrack
August 26, 2004
Andy Friesen wrote:
>> Does that sound reasonable?
> 
> 
> Very!
> 
> [stuff]

... doh.  This is all hogwash because testing against instance data is kind of handy.  Polymorphic contracts aren't optional.

Walter, how did you intend to implement contract inheritance?  If they're just pasted into a method, then they can't be inherited. Implementing them as full-blown methods in their own right means three vtbl entries per method which have to stick around even in release mode lest debug/release builds fail to link.

 -- andy
August 26, 2004
In article <cglbl7$kdq$1@digitaldaemon.com>, Andy Friesen says...
>
>This also opens the doorway to finally implementing contract inheritance without having to store things in the vtbl.
>
>The first thing that came to mind is that contracts on classes accessed through an interface still need to test those contracts, even though which exact contracts are to be tested isn't even known at compile-time.
>  If the caller was responsible for testing contracts, this would be
>impossible.
>
>However, this is completely counter to the spirit of both DbC and interfaces.  The contract is part of the interface, not the implementation.  Logically, then, interfaces need to be able to specify contracts, and methods implementing an interface must be /forbidden/ from specifying contracts of their own. (ditto for abstract classes/methods)

But aren't classes also interfaces?  And what about free functions (though I grant that inheritance issues are not a problem here)?  Or were you just saying that if classes use DbC then those clauses need to be in library headers and not obscured in object code?


Sean


August 26, 2004
>See what I mean?

Ahh yes, thanks for clarifying.  Yes that looks like a good call, and like sean said could be extended for out contracts too.

Charlie

In article <cglaf6$joc$1@digitaldaemon.com>, Arcane Jill says...
>
>In article <cgl94t$j0i$1@digitaldaemon.com>, Charlie says...
>
>>>The resolution is that preconditions must always be executed by the caller, not the callee. That way, caller bugs caused by violating the contract will be found, as they should.
>>
>>Ive lost you here, in what way is 'in' not behaving as you would like, or when does 'in' not catch the conditions ( besides in a release build ? ).  And how can you control who 'executes' the conditions ?
>
>It would have to be done by the compiler. Currently, given the code:
>
>#   // Caller
>#   f(x);
>#
>#   // Callee
>#   int f(uint n)
>#   in { /*precondition*/ }
>#   out(r) { /*postcondition*/ }
>#   body { /*body*/ }
>
>the compiler invisibly transforms it to:
>
>#   // Caller
>#   f(x);
>#
>#   // Callee
>#   int f(uint n)
>#   {
>#       /*precondition*/
>#       /*body*/
>#       /*postcondition*/
>#   }
>
>I would prefer that it instead transform it to:
>
>#   // Caller
>#   /*precondition*/
>#   f(x);
>#
>#   // Callee
>#   int f(uint n)
>#   {
>#       /*body*/
>#       /*postcondition*/
>#   }
>
>See what I mean?
>
>Arcane Jill
>
>


August 26, 2004
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message news:cgl5ni$hfb$1@digitaldaemon.com...
>
> I would very much like this to compile:
>
> #    double squareRoot(double d)
> #    in
> #    {
> #        assert(d >= 0);
> #    };
> #    // function body supplied in linked library
>
> Until yesterday, this compiled, but incorrectly. Walter has now fixed this
bug,
> but he's fixed it in such a way that it now won't compile at all.
>
> The issue is this. A function's "in" contract is a precondition with which /callers/ are expected to comply. If they do not, the bug is in the
callers'
> code, not in the function body. Now, if the function is in a commercial
library,
> the creators of that library may wish to keep their source code to
themselves -
> but they'd still want to expose the precondition.
>
> Worse, the callers' code could still be at the debug stage, while the
library
> code may be a release build - in which case, not only will the application developer not be made aware of the precondition, but it won't even be
executed!
>
> The resolution is that preconditions must always be executed by the
caller, not
> the callee. That way, caller bugs caused by violating the contract will be found, as they should. And these means that it must be possible to expose
an
> "in" contract without exposing the implementation.
>
> Does that sound reasonable?

I think there's a small misunderstanding when it comes to in contracts. Parameter validation for, let's say, operating system API functions, is a requirement for it to be it release builds. That is akin to user input validation, and is not what DbC is for. DbC is for programs that, once debugged, can have the DbC removed. Anything that exposes an interface to arbitrary other code needs to keep its input validation turned on - this would include operating system APIs, DLLs, shared libraries, and COM objects.

If a vendor is shipping libraries meant to be statically linked in, it would be perfectly sensible for them to produce two builds - a 'release' build with DbC turned off, and a 'debug' build with DbC on which the user uses to debug his interface to that library. This does not require that the vendor ship the source or expose the implementation.

(Furthermore, there's a problem with having the caller execute the preconditions - the essential polymorphic aspect of them would be lost.)

If you wish to *add* preconditions to an existing library function, and for good reason do not wish to modify the library source, the right approach is to put a wrapper around it with the DbC in the wrapper.


August 27, 2004
In article <cglsov$tbd$1@digitaldaemon.com>, Walter says...

>I think there's a small misunderstanding when it comes to in contracts. Parameter validation for, let's say, operating system API functions, is a requirement for it to be it release builds. That is akin to user input validation, and is not what DbC is for. DbC is for programs that, once debugged, can have the DbC removed.

I know. I didn't misunderstand.

>Anything that exposes an interface to
>arbitrary other code needs to keep its input validation turned on - this
>would include operating system APIs, DLLs, shared libraries, and COM
>objects.

That is the situation /now/, yes. However, this was a feature request. If preconditions were instead to be done by the caller, that situation would change, and vendors would be able to release only one version of their library.



>If a vendor is shipping libraries meant to be statically linked in, it would be perfectly sensible for them to produce two builds - a 'release' build with DbC turned off, and a 'debug' build with DbC on which the user uses to debug his interface to that library.

Again, this is the situation /now/. I was suggesting that it be changed.


>This does not require that the vendor
>ship the source or expose the implementation.

?

How can you expose the in contract without the implentation? It won't compile! If you mean that vendors may be able to expose:

#    int f( uint n ) in { /*precondition*/ };

then is exactly what I'm asking for. If they can't, how can they possibly expose the precondition without exposing the implementation?

Oh right! You mean they have to cheat. I get it:

#    int f( uint n ) in { /*precondition*/ } body { real_f(n); }

Hmmm. Maybe you should document that, if it's how it's supposed to be done.



>(Furthermore, there's a problem with having the caller execute the preconditions - the essential polymorphic aspect of them would be lost.)

Is it essential? I've been thinking about this (though perhaps now as much as you). Okay, let's say we have a class Stream with precondition that the stream must not have been closed. Now let's say we have a class AlignedStream, deriving from Stream, with additional precondition that the input must always be in multiples of four bytes. You're saying that:

#    Stream s = new AlignedStream();
#    s.write("x");

should check the AlignedStream precondition, not the Stream precondition? I'm not so sure. Shouldn't a derived class always weaken, not strengthen, the precondition? That is, in the above example, AlignedStream shouldn't be deriving from Stream - or should make a runtime check or something. Can this kind of polymorphic aspect work like this? I may have misunderstood this part.



>If you wish to *add* preconditions to an existing library function,

I don't.

Arcane Jill


« First   ‹ Prev
1 2 3