August 26, 2013 Re: Invariants are useless the way they are defined | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 8/26/13 9:47 AM, H. S. Teoh wrote:
> On Mon, Aug 26, 2013 at 06:16:25PM +0200, Timon Gehr wrote:
>> On 08/26/2013 08:49 AM, deadalnix wrote:
>>>
>>> We simply need to add invariant check in the caller, not the callee,
>>> and not introduce them if the caller is itself subject to invariant
>>> insertion when called.
>>
>> The issue with this is that the invariant is not part of the public
>> interface.
>
> The fact that contracts are not part of the public interface greatly
> limits the usefulness of DbC in D. If they *were* part of the public
> interface, there'd be more options to improve it.
You can attach contracts to an interface. What else would need to be done?
Andrei
|
August 26, 2013 Re: Invariants are useless the way they are defined | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Mon, Aug 26, 2013 at 11:01:55AM -0700, Andrei Alexandrescu wrote: > On 8/26/13 9:47 AM, H. S. Teoh wrote: > >On Mon, Aug 26, 2013 at 06:16:25PM +0200, Timon Gehr wrote: > >>On 08/26/2013 08:49 AM, deadalnix wrote: > >>> > >>>We simply need to add invariant check in the caller, not the callee, and not introduce them if the caller is itself subject to invariant insertion when called. > >> > >>The issue with this is that the invariant is not part of the public interface. > > > >The fact that contracts are not part of the public interface greatly limits the usefulness of DbC in D. If they *were* part of the public interface, there'd be more options to improve it. > > You can attach contracts to an interface. What else would need to be done? [...] Sorry, I meant the API, not the OO 'interface'. IIRC, there is a problem with precompiled shared libraries, because the contracts are compiled into the callee rather than the caller, so there is no way for user code to specify whether or not the contracts will be compiled in. If the library was compiled with -release, then no contracts will be included even if the user code was compiled without -release; if the library was compiled without -release, then the contracts will be included even if the user code was compiled with -release. This forces the library vendor to have to ship two versions of the binaries, one compiled with -release, one not. T -- Кто везде - тот нигде. |
August 26, 2013 Re: Invariants are useless the way they are defined | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Monday, 26 August 2013 at 18:15:25 UTC, H. S. Teoh wrote:
> This forces the library vendor to have to ship two versions of the
> binaries, one compiled with -release, one not.
I thought it is a common practice - contracts are not the only troublemakers here, same goes, for example, for debug symbols or bounds checks.
|
August 26, 2013 Re: Invariants are useless the way they are defined | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Monday, 26 August 2013 at 18:25:21 UTC, Dicebot wrote:
> On Monday, 26 August 2013 at 18:15:25 UTC, H. S. Teoh wrote:
>> This forces the library vendor to have to ship two versions of the
>> binaries, one compiled with -release, one not.
>
> I thought it is a common practice - contracts are not the only troublemakers here, same goes, for example, for debug symbols or bounds checks.
Why not have the compiler generate internal versions of all public methods of classes with invariants, which do not perform invariant checking, but contain the actual function body?
class Foo
{
private int bar() const { return 5; }
public int baz() { return bar() * bar(); }
public int third() { return baz() * 2; }
invariant()
{
assert(bar() < 6);
}
}
..gets translated into..
class Foo
{
private int bar() const { return 5; }
public int baz() { invariant(); int r = __internal_baz(); invariant(); return r; }
private int __internal_baz() { return bar() * bar(); }
public int third() { invariant(); int r = __internal_third(); invariant(); return r; }
private int __internal_third() { return baz() * 2; }
invariant()
{
assert(bar() < 6);
}
}
And then in release builds simply avoid doing this generation of __internal_ methods, keeping the ABI (int baz() and int third()) the same.
A variation would be to have __internal_s call __internal_s:
private int __internal_third() { return __internal_baz() * 2; }
but that diminishes ease of debugging.
Anyway, this kind of code transformation is probably impractical for a number of reasons. I just felt like bikeshedding.
|
August 26, 2013 Re: Invariants are useless the way they are defined | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christopher Bergqvist | On Mon, Aug 26, 2013 at 11:47:07PM +0200, Christopher Bergqvist wrote: [...] > Why not have the compiler generate internal versions of all public methods of classes with invariants, which do not perform invariant checking, but contain the actual function body? > > class Foo > { > private int bar() const { return 5; } > public int baz() { return bar() * bar(); } > public int third() { return baz() * 2; } > invariant() > { > assert(bar() < 6); > } > } > > ..gets translated into.. > > class Foo > { > private int bar() const { return 5; } > public int baz() { invariant(); int r = __internal_baz(); > invariant(); return r; } > private int __internal_baz() { return bar() * bar(); } > public int third() { invariant(); int r = __internal_third(); > invariant(); return r; } > private int __internal_third() { return baz() * 2; } > invariant() > { > assert(bar() < 6); > } > } > > And then in release builds simply avoid doing this generation of > __internal_ methods, keeping the ABI (int baz() and int third()) the > same. > > A variation would be to have __internal_s call __internal_s: > private int __internal_third() { return __internal_baz() * 2; } > but that diminishes ease of debugging. > > Anyway, this kind of code transformation is probably impractical for a number of reasons. I just felt like bikeshedding. I like this idea, actually. In fact, it did occur to me when skimming over this thread. I don't see why this code transformation would be impractical -- D *is* quite big on templates and compile-time code generation, after all. :) T -- If you think you are too small to make a difference, try sleeping in a closed room with a mosquito. -- Jan van Steenbergen |
August 27, 2013 Re: Invariants are useless the way they are defined | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix | On 25/08/13 22:16, deadalnix wrote:
> As they are defined now, invariant are plain useless. I find myself
> disabling them one by one in my code as soon as cases get outside simple
> trivia.
>
> The problem is that invariant are checked at the beginning/end on public
> function calls. As a consequence, it is impossible to use any public
> method in an invariant.
>
> For instance, just right now I did refactor a struct to use bitfields,
> in order to make it more compact. Now I have to remove the invariant as
> field access are now function calls.
>
> Another typical situation is when you want to assert certain properties
> in a class hierarchy, where calling virtual method is part of the
> invariant check.
>
> invariant should (and must to be useful) be inserted at callee point,
> when the callee isn't itself subject to invariant insertion, and around
> public memeber manipulation (when the manipulator isn't subject to
> invariant insertion).
>
> Any other pattern it doomed to create infinite recursion for non trivial
> invariant checks.
I just discovered another (surprising to me) shortcoming with the implementation of invariants: namely they don't get checked during the default initiation of a struct. By default, I mean the initialization process that you get when you don't provide a this() method.
This probably doesn't matter in the grand scheme of things as I imagine an instance of the struct that breaks the invariant cant be used without triggering a check. However, for me, it meant I had to use two statements in my unit tests (instead of one) to test the invariant. Also, the deferred triggering of the invariant could make debugging more difficult.
Peter
|
Copyright © 1999-2021 by the D Language Foundation