alwaysAssert() [was: Against enforce()]
Michel Fortin
michel.fortin at michelf.com
Thu Mar 17 18:27:38 PDT 2011
On 2011-03-17 20:31:43 -0400, Walter Bright <newshound2 at digitalmars.com> said:
> On 3/17/2011 5:02 PM, Andrei Alexandrescu wrote:
> > [...]
>
>
> I don't disagree with anything you wrote. But I am suggesting that one
> liners should have a high utility to be justifiably included in Phobos.
>
> ---------------------------------
>
> You mentioned wondering where we should draw the line in using asserts
> to check function inputs as opposed to using enforce. I suggest that
> line should be when a shared library/dll boundary is crossed.
> Statically linked libs should use assert.
>
> The reason is straightforward - a shared library/dll cannot know in
> advance what will be connected to it, so it should treat data coming in
> from an external source as untrusted input. A statically linked
> library, on the other hand, is inextricably bound to a specific caller
> and is debugged/tested as a whole.
>
> This raises the spectre about what to do with Phobos if Phobos is built
> as a dll.
This would be much easier to work with if the decision about checking
"in" contracts was taken at the call site. If user code is compiled
with contracts, any user code calling Phobos would check the contracts
too, dynamic library or not.
One way to make this work is by making the compiler take the contract
as a separate function to call. For instance, this function:
int test(int i)
in {
assert(i >= 0);
}
body {
return 100 / i;
}
would be split in two:
int testContract(int i)
{
assert(i >= 0);
return test(i); // could hard-code tail call optimization here
}
int test(int i) {
return 100 / i;
}
If the function that calls this test function is compiled with
contracts turned on, it substitutes the call to test() for a call to
testContract(), and the contracts gets checked. The testContract()
function does not necessarily need to be part of the library, it can be
instantiated as needed at the call point.
It could even work with virtual functions: if test() is virtual,
testContract() would remain non-virtual and a call to the virtual
function test() would be replaced with a call to the non-virtual
function testContract() (which would be charged to call test).
There's two concerns however:
1. the contract would be checked against the static type instead of the
dynamic type as it is right now. Checking against the dynamic type
would require a new slot on the vtable -- or a separate vtable, perhaps
inside of the ClassInfo -- which would require contracts for public and
protected functions to be part of the library at all times.
2. taking the address of a function (or a delegate) could give you the
one that includes the contract if contracts are turned on, but that
would mean that code compiled with contracts and code compiled without
them would get different addresses for the same function inside of the
same executable, which could break some expectations.
--
Michel Fortin
michel.fortin at michelf.com
http://michelf.com/
More information about the Digitalmars-d
mailing list