|
Archives
D Programming
D
D.gnu
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger
C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows
digitalmars.empire
digitalmars.DMDScript
|
D - Design by contract - detecting reentrancy
↑ ↓ ← → John Nagle <nagle animats.com> writes:
There's been some interest in what's usually called "design by
contract", with "entry", "exit", and "class invariant" assertions.
The class invariants are supposed to be true whenever control
is not within the object. If you take that seriously, you have to
be explicit about when control leaves the object. That's rarely done.
The difficult problem in the single-thread case is deciding
when control has left the via a call, rather than a return. If
a call out of an object results in entering the object reentrantly,
the assumption that the object is in a valid (invariant=true) state
at entry is violated. This often leads to errors. (It's a
common problem inside GUI libraries.)
Does D deal with this problem at all? I haven't seen
any indication that it does.
A starting point would be to provide a way to indicate that
you're leaving an object. I'd once suggested using "public"
for this in C++, so that you'd write a member function like
void foo()
{ x = 1;
public { /* control has left the object */ }
y = 2;
}
Within a "public" block, you can't access private members
of the object. But you can call public methods of the object.
The "public" block is thus "outside" the object.
The class invariant has to be true at the start of a public
block.
If you call a function outside an object from within
a member function, without using a "public" block, then
somehow it must be determined that object-reentry
via recursion is imposible. This is easy to check at run
time, but hard to detect at compile time. It's worth
thinking about conservative compile-time detection of recursion.
Comments?
John Nagle
Animats
↑ ↓ ← → "Walter" <walter digitalmars.com> writes:
The class invariant is called at the entry and exit of each public member
function. I do not see how this can be evaded in the scenario you described.
"John Nagle" <nagle animats.com> wrote in message
news:3BEDDB78.4517D814 animats.com...
There's been some interest in what's usually called "design by
contract", with "entry", "exit", and "class invariant" assertions.
The class invariants are supposed to be true whenever control
is not within the object. If you take that seriously, you have to
be explicit about when control leaves the object. That's rarely done.
The difficult problem in the single-thread case is deciding
when control has left the via a call, rather than a return. If
a call out of an object results in entering the object reentrantly,
the assumption that the object is in a valid (invariant=true) state
at entry is violated. This often leads to errors. (It's a
common problem inside GUI libraries.)
Does D deal with this problem at all? I haven't seen
any indication that it does.
A starting point would be to provide a way to indicate that
you're leaving an object. I'd once suggested using "public"
for this in C++, so that you'd write a member function like
void foo()
{ x = 1;
public { /* control has left the object */ }
y = 2;
}
Within a "public" block, you can't access private members
of the object. But you can call public methods of the object.
The "public" block is thus "outside" the object.
The class invariant has to be true at the start of a public
block.
If you call a function outside an object from within
a member function, without using a "public" block, then
somehow it must be determined that object-reentry
via recursion is imposible. This is easy to check at run
time, but hard to detect at compile time. It's worth
thinking about conservative compile-time detection of recursion.
Comments?
John Nagle
Animats
↑ ↓ ← → John Nagle <nagle animats.com> writes:
If you really know when control is outside the object, you
don't have to check the invariant at entry, just at exit.
Even better, you only have to check the parts of the invariant that
mention variables changed in the function. This allows big invariants
with less overhead.
The other case where control "leaves" the object is when
a thread unlocks a "synchronized" object in the Java sense.
That's "leaving the object", since some other thread can get in.
If the language knows about synchronization, it needs to know
about that.
John Nagle
Animats
Walter wrote:
The class invariant is called at the entry and exit of each public member
function. I do not see how this can be evaded in the scenario you described.
"John Nagle" <nagle animats.com> wrote in message
news:3BEDDB78.4517D814 animats.com...
There's been some interest in what's usually called "design by
contract", with "entry", "exit", and "class invariant" assertions.
The class invariants are supposed to be true whenever control
is not within the object. If you take that seriously, you have to
be explicit about when control leaves the object. That's rarely done.
The difficult problem in the single-thread case is deciding
when control has left the via a call, rather than a return. If
a call out of an object results in entering the object reentrantly,
the assumption that the object is in a valid (invariant=true) state
at entry is violated. This often leads to errors. (It's a
common problem inside GUI libraries.)
Does D deal with this problem at all? I haven't seen
any indication that it does.
A starting point would be to provide a way to indicate that
you're leaving an object. I'd once suggested using "public"
for this in C++, so that you'd write a member function like
void foo()
{ x = 1;
public { /* control has left the object */ }
y = 2;
}
Within a "public" block, you can't access private members
of the object. But you can call public methods of the object.
The "public" block is thus "outside" the object.
The class invariant has to be true at the start of a public
block.
If you call a function outside an object from within
a member function, without using a "public" block, then
somehow it must be determined that object-reentry
via recursion is imposible. This is easy to check at run
time, but hard to detect at compile time. It's worth
thinking about conservative compile-time detection of recursion.
Comments?
John Nagle
Animats
↑ ↓ ← → "Walter" <walter digitalmars.com> writes:
But another thread getting into the object must necessarilly pass through an
invariant first.
"John Nagle" <nagle animats.com> wrote in message
news:3BEED746.2D5B90F5 animats.com...
If you really know when control is outside the object, you
don't have to check the invariant at entry, just at exit.
Even better, you only have to check the parts of the invariant that
mention variables changed in the function. This allows big invariants
with less overhead.
The other case where control "leaves" the object is when
a thread unlocks a "synchronized" object in the Java sense.
That's "leaving the object", since some other thread can get in.
If the language knows about synchronization, it needs to know
about that.
John Nagle
Animats
Walter wrote:
The class invariant is called at the entry and exit of each public
function. I do not see how this can be evaded in the scenario you
"John Nagle" <nagle animats.com> wrote in message
news:3BEDDB78.4517D814 animats.com...
There's been some interest in what's usually called "design by
contract", with "entry", "exit", and "class invariant" assertions.
The class invariants are supposed to be true whenever control
is not within the object. If you take that seriously, you have to
be explicit about when control leaves the object. That's rarely done.
The difficult problem in the single-thread case is deciding
when control has left the via a call, rather than a return. If
a call out of an object results in entering the object reentrantly,
the assumption that the object is in a valid (invariant=true) state
at entry is violated. This often leads to errors. (It's a
common problem inside GUI libraries.)
Does D deal with this problem at all? I haven't seen
any indication that it does.
A starting point would be to provide a way to indicate that
you're leaving an object. I'd once suggested using "public"
for this in C++, so that you'd write a member function like
void foo()
{ x = 1;
public { /* control has left the object */ }
y = 2;
}
Within a "public" block, you can't access private members
of the object. But you can call public methods of the object.
The "public" block is thus "outside" the object.
The class invariant has to be true at the start of a public
block.
If you call a function outside an object from within
a member function, without using a "public" block, then
somehow it must be determined that object-reentry
via recursion is imposible. This is easy to check at run
time, but hard to detect at compile time. It's worth
thinking about conservative compile-time detection of recursion.
Comments?
John Nagle
Animats
↑ ↓ ← → Russell Borogove <kaleja estarcion.com> writes:
John Nagle wrote:
If you really know when control is outside the object, you
don't have to check the invariant at entry, just at exit.
Even better, you only have to check the parts of the invariant that
mention variables changed in the function. This allows big invariants
with less overhead.
It seems to me that checking the invariant on entry, while
redundant in the general case, can also help determine if some
bug has trashed the object between calls.
=RB
↑ ↓ ← → "Walter" <walter digitalmars.com> writes:
"Russell Borogove" <kaleja estarcion.com> wrote in message
news:3BF010A6.9EEE7EAD estarcion.com...
John Nagle wrote:
If you really know when control is outside the object, you
don't have to check the invariant at entry, just at exit.
Even better, you only have to check the parts of the invariant that
mention variables changed in the function. This allows big invariants
with less overhead.
redundant in the general case, can also help determine if some
bug has trashed the object between calls.
Yes. After all, D does have pointers, and you can still have pointer bugs
<g>.
Also, entry invariant checking when combined with the memory stomping of the
delete operator should detect detect dangling reference bugs.
|
|