digitalmars.D.bugs - Nasty invariant bug
- Andy Friesen (30/30) Aug 21 2004 struct Foo {
- Arcane Jill (22/52) Aug 21 2004 There was a thread a while back - though possibly in the other forum - c...
- Matthew (4/64) Aug 21 2004 I'd like to see a reasoned treatment of the consequences of suspending i...
- Bent Rasmussen (21/26) Aug 22 2004 OOSC page 364 and onwards.
- Matthew (3/32) Aug 21 2004 I ran into this myself with the first version of std.recls. Can't rememb...
- Walter (12/22) Aug 22 2004 Yes. Invariant checks are placed at the beginning and end of all public
- Regan Heath (23/48) Aug 22 2004 Can't you simply use a flag, i.e. (lines marked with // are compiler
- Walter (6/35) Aug 23 2004 message
- Arcane Jill (9/11) Aug 23 2004 And don't forget to clear that flag in the event of an exception's being...
- Walter (16/26) Aug 23 2004 thrown!
- Andy Friesen (8/20) Aug 22 2004 One thing I noticed is that invariant calls are handled by the caller,
- Andy Friesen (5/12) Aug 22 2004 errr... I noticed wrong. The invariant is called within the method, not...
- Arcane Jill (26/28) Aug 22 2004 Complicated. Consider this:
- Matthew (7/35) Aug 23 2004 In debug mode, each class instance should have "associated with it" (def...
- antiAlias (33/77) Aug 23 2004 The flag approach has merit, but needs to be appropriately
- Walter (4/13) Aug 23 2004 But then you cannot mix and match debug builds with non-debug builds,
- antiAlias (10/25) Aug 23 2004 Yeah; I can see how that would be desirable. Another approach is for the
- Walter (5/10) Aug 23 2004 and
- antiAlias (14/15) Aug 23 2004 Don't follow you ... if the invariant knows the range of executable
- Walter (5/7) Aug 23 2004 Yes, but it wouldn't solve the problem. The invariant could still call s...
- Bent Rasmussen (1/6) Aug 23 2004 I thought about that too, but isn't that acceptable?
- Walter (3/9) Aug 23 2004 It'll result in infinite recursion.
- Arcane Jill (3/10) Aug 23 2004 That's okay. I don't mind that being an error.
- Nick (43/50) Aug 23 2004 There is a third option, and that is to have the the flags stored outsid...
- Vathix (11/62) Aug 23 2004 nested
struct Foo { int x() { return _x; } void x(int i) { _x = i; } int _x; invariant { assert (x != 13); // guard against bad luck } } int main() { Foo foo; foo.x = 999; int x = foo.x; printf("%i\n", x); return x; } Setting foo.x causes a stack overflow because Foo.x checks the invariant, which calls Foo.x() which itself cheks the invariant again, ad infinitum. This isn't really a bug per se, but I somehow doubt that anybody would ever expect or desire this behaviour. It would be nice if method calls didn't trigger invariant tests from within the invariant itself. If that's unfeasable, a good error message would be sufficient. I think it's pretty safe to say that this one is /way/ too subtle to leave as-is. :) -- andy
Aug 21 2004
In article <cg830p$289n$1 digitaldaemon.com>, Andy Friesen says...struct Foo { int x() { return _x; } void x(int i) { _x = i; } int _x; invariant { assert (x != 13); // guard against bad luck } } int main() { Foo foo; foo.x = 999; int x = foo.x; printf("%i\n", x); return x; } Setting foo.x causes a stack overflow because Foo.x checks the invariant, which calls Foo.x() which itself cheks the invariant again, ad infinitum. This isn't really a bug per se, but I somehow doubt that anybody would ever expect or desire this behaviour. It would be nice if method calls didn't trigger invariant tests from within the invariant itself. If that's unfeasable, a good error message would be sufficient. I think it's pretty safe to say that this one is /way/ too subtle to leave as-is. :) -- andyThere was a thread a while back - though possibly in the other forum - called something like "a temporary relaxation of the class invariant", in which I mentioned a similar problem. I had code which did something like this: Walter's basic response at the time was "well don't do that then - access the variable directly". However, there are sometimes very good reasons why you might /want/ to abstract things away to a getter/setter function, and it /might/ do something a lot more complicated than just reference a variable, so you'd have to cut-and-paste and duplicate code all over the place. This is the kind of place where a #define would be handy - but D's answer to #define (the inline function) checks the damn invariant. I've suggested before that the class invariant should be suspended (that is, not checked) when a function is called from /within/ that class, and only invoked when a member function is called from outside. Sadly, the only realistic workaround we coders can use is to /not/ supply a class invariant in these circumstances. D wants to encourange DbC, but by being /too/ overzealous about checking, it can actually discourage it. I'd like to see this relaxed. Arcane Jill
Aug 21 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:cg89on$2bva$1 digitaldaemon.com...In article <cg830p$289n$1 digitaldaemon.com>, Andy Friesen says...I'd like to see a reasoned treatment of the consequences of suspending invariant calls for all but the outermost instance method call. It sounds nice, and I have no immediate counter arguments, but I think it needs some thinking about.struct Foo { int x() { return _x; } void x(int i) { _x = i; } int _x; invariant { assert (x != 13); // guard against bad luck } } int main() { Foo foo; foo.x = 999; int x = foo.x; printf("%i\n", x); return x; } Setting foo.x causes a stack overflow because Foo.x checks the invariant, which calls Foo.x() which itself cheks the invariant again, ad infinitum. This isn't really a bug per se, but I somehow doubt that anybody would ever expect or desire this behaviour. It would be nice if method calls didn't trigger invariant tests from within the invariant itself. If that's unfeasable, a good error message would be sufficient. I think it's pretty safe to say that this one is /way/ too subtle to leave as-is. :) -- andyThere was a thread a while back - though possibly in the other forum - called something like "a temporary relaxation of the class invariant", in which I mentioned a similar problem. I had code which did something like this: Walter's basic response at the time was "well don't do that then - access the variable directly". However, there are sometimes very good reasons why you might /want/ to abstract things away to a getter/setter function, and it /might/ do something a lot more complicated than just reference a variable, so you'd have to cut-and-paste and duplicate code all over the place. This is the kind of place where a #define would be handy - but D's answer to #define (the inline function) checks the damn invariant. I've suggested before that the class invariant should be suspended (that is, not checked) when a function is called from /within/ that class, and only invoked when a member function is called from outside. Sadly, the only realistic workaround we coders can use is to /not/ supply a class invariant in these circumstances. D wants to encourange DbC, but by being /too/ overzealous about checking, it can actually discourage it. I'd like to see this relaxed.
Aug 21 2004
I'd like to see a reasoned treatment of the consequences of suspending invariant calls for all but the outermost instance method call. It sounds nice, and I have no immediate counter arguments, but I think it needs some thinking about.OOSC page 364 and onwards. "In spite of its name, the invariant does not need to be satisfied at all times..." "it is perfectly acceptable for a procedure g to begin by trying to work towards its goal -- its postcondition -- and in the process to destroy the invariant (as in human affairs, trying to do something useful may disrupt the established order of things); then it spends the second part of its execution trying to restore the invariant without loosing too much of whatever ground has been gained" "Qualified calls of the form a.f ...), executed on behalf of a client, are the only ones that must allways start from a state satisfying the invariant and leave a state satisfying the invariant; there is no such rule for unqualified calls of the form f(...), which are not directly executed by clients but only serve as auxiliary tools for carrying out the needs of qualified calls." Better quotes may be somewhwere, these are just some i dug out. The reasoning is as you can see quite simple. I think the relaxation is justified since its relatively easy for a class to maintain its invariant compared to the same class trying to maintain the invariant of other classes; at least the scope is easier to grasp. But that's just one way of looking at it....
Aug 22 2004
"Andy Friesen" <andy ikagames.com> wrote in message news:cg830p$289n$1 digitaldaemon.com...struct Foo { int x() { return _x; } void x(int i) { _x = i; } int _x; invariant { assert (x != 13); // guard against bad luck } } int main() { Foo foo; foo.x = 999; int x = foo.x; printf("%i\n", x); return x; } Setting foo.x causes a stack overflow because Foo.x checks the invariant, which calls Foo.x() which itself cheks the invariant again, ad infinitum. This isn't really a bug per se, but I somehow doubt that anybody would ever expect or desire this behaviour. It would be nice if method calls didn't trigger invariant tests from within the invariant itself. If that's unfeasable, a good error message would be sufficient. I think it's pretty safe to say that this one is /way/ too subtle to leave as-is. :)I ran into this myself with the first version of std.recls. Can't remember OTTOMH how I got around it, but it was basically an avoidance thing, rather than anything particularly clever.
Aug 21 2004
"Andy Friesen" <andy ikagames.com> wrote in message news:cg830p$289n$1 digitaldaemon.com...Setting foo.x causes a stack overflow because Foo.x checks the invariant, which calls Foo.x() which itself cheks the invariant again, ad infinitum.Yes. Invariant checks are placed at the beginning and end of all public member functions.This isn't really a bug per se, but I somehow doubt that anybody would ever expect or desire this behaviour. It would be nice if method calls didn't trigger invariant tests from within the invariant itself. If that's unfeasable, a good error message would be sufficient.Unfortunately, this is infeasible to implement. There's no way that the invariant compilation can check all possible paths that might result in a call to another public member function, which will cause the infinite recursion. The other way is for the invariant itself to see if it is nested inside a call to itself. This will require either walking the stack, or adding a flag to the object instance data. The former is expensive, and the latter is a problem since the instance layout is already fixed.I think it's pretty safe to say that this one is /way/ too subtle to leave as-is. :)I'll have to document this better.
Aug 22 2004
On Sun, 22 Aug 2004 18:13:30 -0700, Walter <newshound digitalmars.com> wrote:"Andy Friesen" <andy ikagames.com> wrote in message news:cg830p$289n$1 digitaldaemon.com...Can't you simply use a flag, i.e. (lines marked with // are compiler generated) class A { int _i; int i() { return _i; } invariant { assert(i != 13); } } or something?Setting foo.x causes a stack overflow because Foo.x checks the invariant, which calls Foo.x() which itself cheks the invariant again, ad infinitum.Yes. Invariant checks are placed at the beginning and end of all public member functions.This isn't really a bug per se, but I somehow doubt that anybody would ever expect or desire this behaviour. It would be nice if method calls didn't trigger invariant tests from within the invariant itself. If that's unfeasable, a good error message would be sufficient.Unfortunately, this is infeasible to implement. There's no way that the invariant compilation can check all possible paths that might result in a call to another public member function, which will cause the infinite recursion. The other way is for the invariant itself to see if it is nested inside a call to itself. This will require either walking the stack, or adding a flag to the object instance data. The former is expensive, and the latter is a problem since the instance layout is already fixed.Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/I think it's pretty safe to say that this one is /way/ too subtle to leave as-is. :)I'll have to document this better.
Aug 22 2004
"Regan Heath" <regan netwin.co.nz> wrote in message news:opsc5vqgsx5a2sq9 digitalmars.com...On Sun, 22 Aug 2004 18:13:30 -0700, Walter <newshound digitalmars.com> wrote:message"Andy Friesen" <andy ikagames.com> wrote in message news:cg830p$289n$1 digitaldaemon.com...Setting foo.x causes a stack overflow because Foo.x checks the invariant, which calls Foo.x() which itself cheks the invariant again, ad infinitum.Yes. Invariant checks are placed at the beginning and end of all public member functions.This isn't really a bug per se, but I somehow doubt that anybody would ever expect or desire this behaviour. It would be nice if method calls didn't trigger invariant tests from within the invariant itself. If that's unfeasable, a good errorawould be sufficient.Unfortunately, this is infeasible to implement. There's no way that the invariant compilation can check all possible paths that might result inThat's the "add a flag to the object instance data" method. The trouble there is it will add size to every object.call to another public member function, which will cause the infinite recursion. The other way is for the invariant itself to see if it is nested inside a call to itself. This will require either walking the stack, or adding a flag to the object instance data. The former is expensive, and the latter is a problem since the instance layout is already fixed.Can't you simply use a flag, i.e. (lines marked with // are compiler generated)
Aug 23 2004
In article <cgc9l7$24u2$1 digitaldaemon.com>, Walter says...That's the "add a flag to the object instance data" method. The trouble there is it will add size to every object.And don't forget to clear that flag in the event of an exception's being thrown! Maybe you'd better make it a flag wrapped in an auto class. I don't know too much about how vtbls are implemented, but I would have thought that my debug build (two-entry-points for each member function, two-vtbls) idea would solve the problem with no additional exception handling required. It would add size to each class (a second vtbl, and glue-code for each function), but only in a debug build. Jill
Aug 23 2004
"Arcane Jill" <Arcane_member pathlink.com> wrote in message news:cgck5t$2am9$1 digitaldaemon.com...In article <cgc9l7$24u2$1 digitaldaemon.com>, Walter says...thrown!That's the "add a flag to the object instance data" method. The trouble there is it will add size to every object.And don't forget to clear that flag in the event of an exception's beingMaybe you'd better make it a flag wrapped in an auto class. I don't know too much about how vtbls are implemented, but I would havethoughtthat my debug build (two-entry-points for each member function, two-vtbls)ideawould solve the problem with no additional exception handling required. Itwouldadd size to each class (a second vtbl, and glue-code for each function),butonly in a debug build.It would not solve the problem. All the invariant would have to do is: void bar(Foo f) { f.func(); } class Foo { void func(Foo f) { } invariant { bar(this); } }
Aug 23 2004
Walter wrote:One thing I noticed is that invariant calls are handled by the caller, not the callee. Would it be feasable for internal method calls to skip the invariant test? This would be reasonable behaviour in the majority of cases, I would think. In those cases when it isn't, an explicit "assert(this);" is easy enough to write. -- andyIt would be nice if method calls didn't trigger invariant tests from within the invariant itself. If that's unfeasable, a good error message would be sufficient.Unfortunately, this is infeasible to implement. There's no way that the invariant compilation can check all possible paths that might result in a call to another public member function, which will cause the infinite recursion. The other way is for the invariant itself to see if it is nested inside a call to itself. This will require either walking the stack, or adding a flag to the object instance data. The former is expensive, and the latter is a problem since the instance layout is already fixed.
Aug 22 2004
Andy Friesen wrote:One thing I noticed is that invariant calls are handled by the caller, not the callee. Would it be feasable for internal method calls to skip the invariant test? This would be reasonable behaviour in the majority of cases, I would think. In those cases when it isn't, an explicit "assert(this);" is easy enough to write.errr... I noticed wrong. The invariant is called within the method, not by the caller. Is it feasable to turn this around? -- andy
Aug 22 2004
In article <cgbl12$1mf1$1 digitaldaemon.com>, Andy Friesen says...errr... I noticed wrong. The invariant is called within the method, not by the caller. Is it feasable to turn this around?Complicated. Consider this: Suppose I release a library L, and someone else develops an application A which statically links with L. Let us suppose that L has been through its developmental phase, so now there's only a release build of it. A, on the other hand, is still being developed, and so is being compiled in debug build. So when A calls a function in L, I would /hope/ that the "in" preconditions of functions within L will still be tested. (Preconditions are there, after all, to help callers find bugs in /their/ code). This can only happen if preconditions are handled by the caller, not the callee. For class invariants, it should be allowed for the invariant to be temporarily broken when inside member functions, and therefore it should only be checked when called from outside. One way to achieve this is by placing responsibility on the callee. /However/, once the callee (the library L) goes into release build, the invariant should not be checked at all, regardless of the debug/release state of the caller (the application A). Think about it. One solution is to give two entry-points to each member function (but only in debug build) - one for use when the function is called from inside the class (i.e. for calls of the form f(...)) which does not call the invariant test, and one for functions called from outside the class (i.e. for calls on the form a.f(...)) which does. In a release build, those two entry points collapse to one. I think this could be done by giving each class a separate "vtbl for internal calls" in a debug build. Only for postconditions does it makes sense for the callee to perform the test regardless of whence the call came. Arcane Jill
Aug 22 2004
In debug mode, each class instance should have "associated with it" (defined below) a flag that indicates whether we're "in" that instance's methods, and invariants are then suspended. If it's not appropriate to have the flag in each instance, then each classinfo could have a debug-time mapping between instance (pointer) and the flag. I'm guessing that there are complications to this, but this may at least be a step forward. Discuss ... "Arcane Jill" <Arcane_member pathlink.com> wrote in message news:cgc32m$201f$1 digitaldaemon.com...In article <cgbl12$1mf1$1 digitaldaemon.com>, Andy Friesen says...errr... I noticed wrong. The invariant is called within the method, not by the caller. Is it feasable to turn this around?Complicated. Consider this: Suppose I release a library L, and someone else develops an application A which statically links with L. Let us suppose that L has been through its developmental phase, so now there's only a release build of it. A, on the other hand, is still being developed, and so is being compiled in debug build. So when A calls a function in L, I would /hope/ that the "in" preconditions of functions within L will still be tested. (Preconditions are there, after all, to help callers find bugs in /their/ code). This can only happen if preconditions are handled by the caller, not the callee. For class invariants, it should be allowed for the invariant to be temporarily broken when inside member functions, and therefore it should only be checked when called from outside. One way to achieve this is by placing responsibility on the callee. /However/, once the callee (the library L) goes into release build, the invariant should not be checked at all, regardless of the debug/release state of the caller (the application A). Think about it. One solution is to give two entry-points to each member function (but only in debug build) - one for use when the function is called from inside the class (i.e. for calls of the form f(...)) which does not call the invariant test, and one for functions called from outside the class (i.e. for calls on the form a.f(...)) which does. In a release build, those two entry points collapse to one. I think this could be done by giving each class a separate "vtbl for internal calls" in a debug build. Only for postconditions does it makes sense for the callee to perform the test regardless of whence the call came. Arcane Jill
Aug 23 2004
The flag approach has merit, but needs to be appropriately exception-checked; worse, it's not thread safe. You'd potentially need to use thread locals instead. A different approach would be for the function-calling protocol to be modified slightly in debug mode: a flag gets pushed onto the stack by the caller, indicating whether or not invariants should execute. Those methods within the class itself push a 'false' for their own methods, while all external calls push a 'true' instead. No exception issues; no thread-safety issues. "Matthew" <admin.hat stlsoft.dot.org> wrote in message news:cgc57s$21ko$1 digitaldaemon.com...In debug mode, each class instance should have "associated with it"(defined below) a flag that indicates whether we're"in" that instance's methods, and invariants are then suspended. If it's not appropriate to have the flag in each instance, then eachclassinfo could have a debug-time mapping betweeninstance (pointer) and the flag. I'm guessing that there are complications to this, but this may at leastbe a step forward.Discuss ... "Arcane Jill" <Arcane_member pathlink.com> wrote in messagenews:cgc32m$201f$1 digitaldaemon.com...notIn article <cgbl12$1mf1$1 digitaldaemon.com>, Andy Friesen says...errr... I noticed wrong. The invariant is called within the method,A whichby the caller. Is it feasable to turn this around?Complicated. Consider this: Suppose I release a library L, and someone else develops an applicationthe otherstatically links with L. Let us suppose that L has been through its developmental phase, so now there's only a release build of it. A, onpreconditions ofhand, is still being developed, and so is being compiled in debug build. So when A calls a function in L, I would /hope/ that the "in"all, tofunctions within L will still be tested. (Preconditions are there, afterpreconditionshelp callers find bugs in /their/ code). This can only happen iftemporarilyare handled by the caller, not the callee. For class invariants, it should be allowed for the invariant to becheckedbroken when inside member functions, and therefore it should only beresponsibilitywhen called from outside. One way to achieve this is by placingreleaseon the callee. /However/, once the callee (the library L) goes intoOnebuild, the invariant should not be checked at all, regardless of the debug/release state of the caller (the application A). Think about it.in debugsolution is to give two entry-points to each member function (but only(i.e. forbuild) - one for use when the function is called from inside the classone forcalls of the form f(...)) which does not call the invariant test, anda.f(...))functions called from outside the class (i.e. for calls on the formI thinkwhich does. In a release build, those two entry points collapse to one.calls" inthis could be done by giving each class a separate "vtbl for internalthe testa debug build. Only for postconditions does it makes sense for the callee to performregardless of whence the call came. Arcane Jill
Aug 23 2004
"antiAlias" <fu bar.com> wrote in message news:cgd6r6$2jn8$1 digitaldaemon.com...The flag approach has merit, but needs to be appropriately exception-checked; worse, it's not thread safe. You'd potentially need to use thread locals instead. A different approach would be for the function-calling protocol to be modified slightly in debug mode: a flag gets pushed onto the stack by the caller, indicating whether or not invariants should execute. Those methods within the class itself push a 'false' for their own methods, while all external calls push a 'true' instead. No exception issues; no thread-safety issues.But then you cannot mix and match debug builds with non-debug builds, significantly reducing their utility.
Aug 23 2004
Yeah; I can see how that would be desirable. Another approach is for the invariant to check the return address; if it's within the range of the current module then don't execute. That way, all the effort is contained and performed by the invariant itself. You might even expose that as an optional invariant-type ... "Walter" <newshound digitalmars.com> wrote in message news:cgdbvt$2nht$2 digitaldaemon.com..."antiAlias" <fu bar.com> wrote in message news:cgd6r6$2jn8$1 digitaldaemon.com...toThe flag approach has merit, but needs to be appropriately exception-checked; worse, it's not thread safe. You'd potentially needtheuse thread locals instead. A different approach would be for the function-calling protocol to be modified slightly in debug mode: a flag gets pushed onto the stack bymethodscaller, indicating whether or not invariants should execute. Thosewithin the class itself push a 'false' for their own methods, while all external calls push a 'true' instead. No exception issues; no thread-safety issues.But then you cannot mix and match debug builds with non-debug builds, significantly reducing their utility.
Aug 23 2004
"antiAlias" <fu bar.com> wrote in message news:cgdhln$2que$1 digitaldaemon.com...Yeah; I can see how that would be desirable. Another approach is for the invariant to check the return address; if it's within the range of the current module then don't execute. That way, all the effort is containedandperformed by the invariant itself. You might even expose that as anoptionalinvariant-type ...I don't see how any calls to the invariant can work, then <g>.
Aug 23 2004
"Walter" <newshound digitalmars.com> wrote in message news:cgdm0d$2ub8$1 digitaldaemon.com...I don't see how any calls to the invariant can work, then <g>.Don't follow you ... if the invariant knows the range of executable addresses within the containing module, it can accept calls from without the range whilst ignoring those from within. The compiler would have to setup begin & end labels for the code generated within the containing module (or something like that), the linker/loader would patch them in the usual manner to represent real addresses, and the invariant would check the address of said labels against the provided return-address (from the stack) to see if it's being called from within the same (containing) module. Calls from a different module will have a return-address that is outside the range of the called module and, therefore, the invariant would execute. Am I missing something here?
Aug 23 2004
I am, of course, using the term 'module' to loosely mean D source-file. "antiAlias" <fu bar.com> wrote in message news:cgdmnf$2v2t$1 digitaldaemon.com..."Walter" <newshound digitalmars.com> wrote in message news:cgdm0d$2ub8$1 digitaldaemon.com...theI don't see how any calls to the invariant can work, then <g>.Don't follow you ... if the invariant knows the range of executable addresses within the containing module, it can accept calls from withoutrange whilst ignoring those from within. The compiler would have to setup begin & end labels for the code generated within the containing module (or something like that), the linker/loader would patch them in the usual manner to represent real addresses, and the invariant would check the address of said labels against the provided return-address (from the stack) to see if it's being called from withinthesame (containing) module. Calls from a different module will have a return-address that is outsidetherange of the called module and, therefore, the invariant would execute. Am I missing something here?
Aug 23 2004
Ahhh ... right. I am missing something. The invariant is invoked by the callee, not the caller ... whoops. Is there a known stack-frame you can peek at? You'd only be looking one frame removed (the call immediately prior to the invariant call) ... I think it's fair to say that circuitous routes /will/ invoke the invariant. "antiAlias" <fu bar.com> wrote in message news:cgdmnf$2v2t$1 digitaldaemon.com..."Walter" <newshound digitalmars.com> wrote in message news:cgdm0d$2ub8$1 digitaldaemon.com...theI don't see how any calls to the invariant can work, then <g>.Don't follow you ... if the invariant knows the range of executable addresses within the containing module, it can accept calls from withoutrange whilst ignoring those from within. The compiler would have to setup begin & end labels for the code generated within the containing module (or something like that), the linker/loader would patch them in the usual manner to represent real addresses, and the invariant would check the address of said labels against the provided return-address (from the stack) to see if it's being called from withinthesame (containing) module. Calls from a different module will have a return-address that is outsidetherange of the called module and, therefore, the invariant would execute. Am I missing something here?
Aug 23 2004
"antiAlias" <fu bar.com> wrote in message news:cgdnbq$2vhn$1 digitaldaemon.com...Ahhh ... right. I am missing something. The invariant is invoked by the callee, not the caller ... whoops. Is there a known stack-frame you canpeekat? You'd only be looking one frame removed (the call immediately prior to the invariant call) ... I think it's fair to say that circuitous routes /will/ invoke the invariant.It starts getting fairly complicated handling all the special cases when one starts doing that.
Aug 23 2004
"Walter" <newshound digitalmars.com> wrote in message news:cgdvem$351$1 digitaldaemon.com..."antiAlias" <fu bar.com> wrote in message news:cgdnbq$2vhn$1 digitaldaemon.com...toAhhh ... right. I am missing something. The invariant is invoked by the callee, not the caller ... whoops. Is there a known stack-frame you canpeekat? You'd only be looking one frame removed (the call immediately prioronethe invariant call) ... I think it's fair to say that circuitous routes /will/ invoke the invariant.It starts getting fairly complicated handling all the special cases whenstarts doing that.That sounds intriguing. I can imagine special-cases via support for other languages, but from within D itself, I'm at a loss to speculate. Care to elaborate a little? Special-cases aside; would this not be a viable solution, given that it avoids exception and thread-safety issues?
Aug 23 2004
"antiAlias" <fu bar.com> wrote in message news:cgeoip$fcn$1 digitaldaemon.com..."Walter" <newshound digitalmars.com> wrote in message news:cgdvem$351$1 digitaldaemon.com...the"antiAlias" <fu bar.com> wrote in message news:cgdnbq$2vhn$1 digitaldaemon.com...Ahhh ... right. I am missing something. The invariant is invoked bycancallee, not the caller ... whoops. Is there a known stack-frame youpriorpeekat? You'd only be looking one frame removed (the call immediatelytoroutesthe invariant call) ... I think it's fair to say that circuitousThe compiler generates different stack frames based on things like optimization settings, debugging, exception handling, etc. Then there are the multiple calling conventions, each with their own way of doing things.one/will/ invoke the invariant.It starts getting fairly complicated handling all the special cases whenstarts doing that.That sounds intriguing. I can imagine special-cases via support for other languages, but from within D itself, I'm at a loss to speculate. Care to elaborate a little? Special-cases aside; would this not be a viable solution, given that it avoids exception and thread-safety issues?
Aug 24 2004
"Walter" <newshound digitalmars.com> wroteThe compiler generates different stack frames based on things like optimization settings, debugging, exception handling, etc. Then there are the multiple calling conventions, each with their own way of doing things.Thanks!
Aug 24 2004
"Andy Friesen" <andy ikagames.com> wrote in message news:cgbk5c$1ls4$1 digitaldaemon.com...Would it be feasable for internal method calls to skip the invariant test?Yes, but it wouldn't solve the problem. The invariant could still call some external function, which could then call a member function, which would then invoke the invariant agian.
Aug 23 2004
Yes, but it wouldn't solve the problem. The invariant could still call some external function, which could then call a member function, which would then invoke the invariant agian.I thought about that too, but isn't that acceptable?
Aug 23 2004
"Bent Rasmussen" <exo bent-rasmussen.info> wrote in message news:cgcfrh$28bh$1 digitaldaemon.com...It'll result in infinite recursion.Yes, but it wouldn't solve the problem. The invariant could still call some external function, which could then call a member function, which would then invoke the invariant agian.I thought about that too, but isn't that acceptable?
Aug 23 2004
In article <cgc9l8$24u2$2 digitaldaemon.com>, Walter says..."Andy Friesen" <andy ikagames.com> wrote in message news:cgbk5c$1ls4$1 digitaldaemon.com...That's okay. I don't mind that being an error. JillWould it be feasable for internal method calls to skip the invariant test?Yes, but it wouldn't solve the problem. The invariant could still call some external function, which could then call a member function, which would then invoke the invariant agian.
Aug 23 2004
In article <cgbgqa$1jql$1 digitaldaemon.com>, Walter says...Unfortunately, this is infeasible to implement. There's no way that the invariant compilation can check all possible paths that might result in a call to another public member function, which will cause the infinite recursion. The other way is for the invariant itself to see if it is nested inside a call to itself. This will require either walking the stack, or adding a flag to the object instance data. The former is expensive, and the latter is a problem since the instance layout is already fixed.There is a third option, and that is to have the the flags stored outside the object instance itself. This could for example be done using an associative array with 'this' as an index, see example below. (By the way, using return; inside invariants (and unittests?) seems to work, it should probably be documented.) Is this doable, or is it way too expensive? Nick
Aug 23 2004
"Nick" <Nick_member pathlink.com> wrote in message news:cgcjin$2ad2$1 digitaldaemon.com...In article <cgbgqa$1jql$1 digitaldaemon.com>, Walter says...nestedUnfortunately, this is infeasible to implement. There's no way that the invariant compilation can check all possible paths that might result in a call to another public member function, which will cause the infinite recursion. The other way is for the invariant itself to see if it istheinside a call to itself. This will require either walking the stack, or adding a flag to the object instance data. The former is expensive, andthelatter is a problem since the instance layout is already fixed.There is a third option, and that is to have the the flags stored outsideobject instance itself. This could for example be done using anassociativearray with 'this' as an index, see example below. (By the way, usingreturn;inside invariants (and unittests?) seems to work, it should probably be documented.) Is this doable, or is it way too expensive? NickIt's not thread safe. All member function calls would have to be synchronized, eek! I wouldn't mind having the compiler tack on an extra bit to my class; it's just debug code.
Aug 23 2004