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

>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.

I see only one version of phobos.lib in my download.
Does it have DbC enabled?

Jill




August 27, 2004
Walter wrote:

<snip>
> 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.

I disagree.  The end user isn't going to be calling OS API functions directly, any more than functions in the library being talked about or functions in the app itself.

> 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.
<snip>

Indeed.  Obviously an app wouldn't pass potentially bad user input to an API if the only check is DbC.  It would do user input validation first.

AIUI, the OP's request is for the DbC validation to work in those situations when it should, and when it is correct to use DbC - for checking that the application (not the user) is passing valid arguments to lib functions.  This is part of the Phobos philosophy, isn't it?

Stewart.

-- 
My e-mail is valid but not my primary mailbox.  Please keep replies on
the 'group where everyone may benefit.
August 27, 2004
Walter wrote:
> 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.

What about the reasons I posted?  Contracts are useful for optimization, and for making sure that later versions of a library haven't chosen to abandon some contracts that they used to obey.

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

Not necessarily.  As I undertsand it, we currently have contracts that work like this:

void CalledFunction(<whatever>) {
  /* in contracts */
  /* body */
  /* out contracts */
}

Which is good, and is polymorphic.  Don't change that.  What I think is that when you have a function without a body, you should *add* these tests to the caller:
  /* in contracts */
  CalledFunction(<whatever>);
  /* out contracts */

This retains polymorphism but also allows us to assert things about libraries for which we don't have the source.  Yeah, it means that the assert()s are run twice, but, as you note, contracts are designed for debug builds, not release builds.  Plus, it lets us run contracts even if the vendor only gave us a release build.



Of course, this leads us quite quickly back to the question of contracts on interfaces and on delegates.  The callee could add the contracts to his own code in those cases, as well...

> 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.

Yeah, but that's ugly...

August 27, 2004
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message news:cgmni7$1a9p$1@digitaldaemon.com...
> >This does not require that the vendor
> >ship the source or expose the implementation.
>
> ?
>
> How can you expose the in contract without the implentation?

You don't need to expose the contract - the contract just has to be executed. It can be executed in compiled form by the library, so the library (compiled with DbC on) doesn't need to ship the source.


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

Yes. Bertrand Meyer goes through it all in his book on the topic "Object-Oriented Software Construction". He shows how it is essential for polymorphic functions to have polymorphic pre/post conditions.

> 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?

A derived class weakens the precondition in that either the base precondition must be true OR the derived precondition. But when you have a reference to a base class, you do not know if is in reality a derived class, so you do not know which preconditions to check.


August 27, 2004
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message news:cgmrdh$1bal$1@digitaldaemon.com...
> In article <cglsov$tbd$1@digitaldaemon.com>, Walter says...
>
> >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.
>
> I see only one version of phobos.lib in my download.
> Does it have DbC enabled?

No. But it does come with source, and you can adjust the makefile to compile it with DbC on.


August 28, 2004
"Stewart Gordon" <smjg_1998@yahoo.com> wrote in message news:cgn0jc$1deu$1@digitaldaemon.com...
> Walter wrote:
>
> <snip>
> > 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.
>
> I disagree.  The end user isn't going to be calling OS API functions directly, any more than functions in the library being talked about or functions in the app itself.

Yes, they do. I call OS API functions all the time in my code.

> > 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.
> <snip>
> Indeed.  Obviously an app wouldn't pass potentially bad user input to an
> API if the only check is DbC.  It would do user input validation first.

Any OS API or DLL interface must consider all programs trying to connect to its functions as rogue, and must do parameter validation on them.



August 28, 2004
"Russ Lewis" <spamhole-2001-07-16@deming-os.org> wrote in message news:cgnpqm$1rrr$1@digitaldaemon.com...
> What about the reasons I posted?  Contracts are useful for optimization, and for making sure that later versions of a library haven't chosen to abandon some contracts that they used to obey.

That's true, contracts are possibly valuable hints for optimization.

> > (Furthermore, there's a problem with having the caller execute the preconditions - the essential polymorphic aspect of them would be lost.)
>
> Not necessarily.  As I undertsand it, we currently have contracts that work like this:
>
> void CalledFunction(<whatever>) {
>    /* in contracts */
>    /* body */
>    /* out contracts */
> }
>
> Which is good, and is polymorphic.  Don't change that.  What I think is
> that when you have a function without a body, you should *add* these
> tests to the caller:
>    /* in contracts */
>    CalledFunction(<whatever>);
>    /* out contracts */
>
> This retains polymorphism but also allows us to assert things about libraries for which we don't have the source.  Yeah, it means that the assert()s are run twice, but, as you note, contracts are designed for debug builds, not release builds.  Plus, it lets us run contracts even if the vendor only gave us a release build.

It still breaks polymorphism. If you have:
    class A { void foo() in { ... } body { ... } }
    class B:A { void foo() in { ... } body { ... } }
    ...
    A a;
    ...
    a.foo();

you'll be calling B.foo(), not A.foo(), and A.foo()'s preconditions do not
apply.


August 28, 2004
Walter wrote:
> It still breaks polymorphism. If you have:
>     class A { void foo() in { ... } body { ... } }
>     class B:A { void foo() in { ... } body { ... } }
>     ...
>     A a;
>     ...
>     a.foo();
> 
> you'll be calling B.foo(), not A.foo(), and A.foo()'s preconditions do not
> apply.

Should they?  It /is/ an A, after all.  Shouldn't it be expected to behave like one?

Polymorphic preconditions could (hypothetically) produce subtle bugs in code that satisfies the conditions set forth by an ancestor of A, but not A itself.

(I haven't read any of Bertrand Meyer's writings, though, so I shall assume that I am wrong regardless)

Also, how is DMD going to cope with inheriting a class whose source is not available?  The contracts can't loosen/tighten properly if you don't know what they are.

 -- andy
August 28, 2004
Andy Friesen wrote:
> Walter wrote:
> 
>> It still breaks polymorphism. If you have:
>>     class A { void foo() in { ... } body { ... } }
>>     class B:A { void foo() in { ... } body { ... } }
>>     ...
>>     A a;
>>     ...
>>     a.foo();
>>
>> you'll be calling B.foo(), not A.foo(), and A.foo()'s preconditions do not
>> apply.
> 
> Should they?  It /is/ an A, after all.  Shouldn't it be expected to behave like one?

Right!  It should be valid for the caller to assert A's preconditions, because the caller doesn't know about the fact that B loosened them. Likewise, the caller can assert A's postconditions, even though B may have tightened them.

Frankly, I'm starting to think that this *should* be done.  I'm thinking that the following code should be an error:

class A   { void foo(int i) in { assert(i> 0); } body {} }
class B:A { void foo(int i) in { assert(i>=0); } body {} }
A a = new B;
a.foo(0);	// assert should fail here

So code, in order to work would have to do this:
B b = cast(B)a;
b.foo(0);	// ok, uses B's preconditions

August 30, 2004
Walter wrote:
> 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.

I strongly disagree.

The basic question here is: who is to be trusted? Should a library trust the application to do the calls correctly? This is basically a design decision: for distributed systems, like the COM objects you are talking about, I agree that every object should thoroughly check any input it gets. The individual objects are rather weakly linked with each other, so each one should take care of it's own integrity.

For DLLs, though, the matter is different: The code of the DLL runs under the same priviledges as the code of the application. In principle, the application has all the power to fiddle with the data of the DLL or walk around the interface in any way it likes. It is the responsibility of the application programmer not to abuse this power. It is not up to the library to put up safeguards.

Whether or not the in-contracts of a library need to be checked depends on the stability of the application. There is no difference whether it is a static or dynamic library. True, a DLL can be linked in a different version, but whatever version you use, it has to follow the correct interface. Contracts are part of the interface. If you change the interface, be prepared to recompile the application.

Therefore: in-contracts should be checked by the caller, and it depends on the stability of the caller whether this check has to be performed. Any check of the user-input or other untrusted data has to be performed before the check of the in-contract.

> 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.

There is no point at all in shipping "debug"-compiles of a library. If the library code is correct, out-contracts and invariants need not be checked. On the other hand - no matter how correct the library is: it is up to the application developer to decide whether in-contracts need to be checked.

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

The worry about breaking polymorphism is totally unfounded: Already, there is the rule, that in-contracts are "or"ed together in inheriting classes. If you call a method on a class reference, you can always check the in-contracts of the reference class, even if the class of the object class is a subclass of that. If the check passes, this will be fine in any case (because of the "or" rule)

Furthermore: the in-contracts may only depend on public information about a class. There is no point of talking about a "contract" if one of the parties cannot check whether it is kept.