Thread overview | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
October 26, 2011 [Issue 6856] New: Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
http://d.puremagic.com/issues/show_bug.cgi?id=6856 Summary: Preconditions are not inherited Product: D Version: D2 Platform: Other OS/Version: All Status: NEW Severity: normal Priority: P2 Component: DMD AssignedTo: nobody@puremagic.com ReportedBy: timon.gehr@gmx.ch --- Comment #0 from timon.gehr@gmx.ch 2011-10-26 13:58:18 PDT --- Precondition inheritance does not work in a satisfying way: import std.stdio; class A{ void foo()in{writeln("in!");}out{writeln("out!");}body{} } class B:A{ override void foo(){} // add in{assert(false);}body to get it working } void main(){ A x = new A; x.foo(); // in! \ out! B y = new B; y.foo(); // out! } If the child class does not specify an in contract on an overriding method, the in contract of the parent should be inherited, without adding a contract that always passes. The current behavior makes it too easy to inadvertently widen the interface and have undetected bugs. Chapter 10.9 in TDPL does not explicitly mention the fact that it is supposed to work that way, but it seems to assume it. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
October 30, 2011 [Issue 6856] Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
Posted in reply to timon.gehr@gmx.ch | http://d.puremagic.com/issues/show_bug.cgi?id=6856 Stewart Gordon <smjg@iname.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |smjg@iname.com --- Comment #1 from Stewart Gordon <smjg@iname.com> 2011-10-29 18:20:20 PDT --- http://www.digitalmars.com/d/1.0/dbc.html "If a function in a derived class overrides a function in its super class, then only one of the in contracts of the function and its base functions must be satisfied. Overriding functions then becomes a process of loosening the in contracts. A function without an in contract means that any values of the function parameters are allowed." On an override, the semantics of an in contract are to _add_ to what is a legal call of the method. And the absence of an in contract in a function definition is really syntactic sugar for an empty in contract. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
November 01, 2011 [Issue 6856] Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
Posted in reply to timon.gehr@gmx.ch | http://d.puremagic.com/issues/show_bug.cgi?id=6856 Leandro Lucarella <llucax@gmail.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |llucax@gmail.com Version|D2 |D1 & D2 --- Comment #2 from Leandro Lucarella <llucax@gmail.com> 2011-11-01 05:25:05 PDT --- What about this: extern (C) int printf(char* s, ...); class X { void f() in { printf("\tX.f() in\n"); } body {} } class Y : X { override void f() in { printf("\tY.f() in\n"); } body {} } class Z : Y { override void f() body {} } void main() { printf("X x\n"); X xx = new X; xx.f(); printf("\t---\n"); printf("X y\n"); X xy = new Y; xy.f(); printf("\t---\n"); printf("X z\n"); X xz = new Z; xz.f(); printf("\t---\n"); printf("--------------------\n"); printf("Y y\n"); Y yy = new Y; yy.f(); printf("\t---\n"); printf("Y z\n"); Y yz = new Z; yz.f(); printf("\t---\n"); printf("--------------------\n"); printf("Z z\n"); Z z = new Z; z.f(); printf("\t---\n"); } It prints: X x X.f() in --- X y X.f() in --- X z --- -------------------- Y y X.f() in --- Y z --- -------------------- Z z --- Shouldn't "Y y" print "Y.f()" if Y can loose the in contract? Shouldn't "X z" and "Y z" print *something* (probably "X.f()" and "Y.f()" respectively)? -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
November 01, 2011 [Issue 6856] Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
Posted in reply to timon.gehr@gmx.ch | http://d.puremagic.com/issues/show_bug.cgi?id=6856 --- Comment #3 from Leandro Lucarella <llucax@gmail.com> 2011-11-01 05:27:32 PDT --- BTW, that was DMD 1.071. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
November 01, 2011 [Issue 6856] Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
Posted in reply to timon.gehr@gmx.ch | http://d.puremagic.com/issues/show_bug.cgi?id=6856 --- Comment #4 from Leandro Lucarella <llucax@gmail.com> 2011-11-01 05:46:43 PDT --- BTW, "in" contracts seems to be very ill defined, because overriding a method with an "in" contract without specifying an "in" contract should inherit the contract from the base class/interface, not remove the contract completely. You have to repeat the contract from the base class manually, that sucks. There should be some syntax to remove the contract instead, maybe something like: void f() in delete body { // ... } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
November 01, 2011 [Issue 6856] Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
Posted in reply to timon.gehr@gmx.ch | http://d.puremagic.com/issues/show_bug.cgi?id=6856 --- Comment #5 from timon.gehr@gmx.ch 2011-11-01 05:57:01 PDT --- @Leandro: Your first example is okay. The precondition test shortcuts. It is more or less equivalent to passes(X_foo_in) || passes(Y_foo_in). If passes(X_foo_in), then the second part does not have to be evaluated, ergo it never prints "Y.f() in". The fact that in order to just inherit an in contract it is necessary to add an in{assert(0);} contract is hopefully just an oversight and not by design. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
November 01, 2011 [Issue 6856] Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
Posted in reply to timon.gehr@gmx.ch | http://d.puremagic.com/issues/show_bug.cgi?id=6856 --- Comment #6 from timon.gehr@gmx.ch 2011-11-01 05:59:14 PDT --- (In reply to comment #4) > BTW, "in" contracts seems to be very ill defined, because overriding a method with an "in" contract without specifying an "in" contract should inherit the contract from the base class/interface, not remove the contract completely. You have to repeat the contract from the base class manually, that sucks. There should be some syntax to remove the contract instead, maybe something like: > > void f() > in delete > body > { > // ... > } I think it should just look like this: override void f() in{}body{ // ... } If no explicit contract is added, it should be inherited. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
November 01, 2011 [Issue 6856] Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
Posted in reply to timon.gehr@gmx.ch | http://d.puremagic.com/issues/show_bug.cgi?id=6856 --- Comment #7 from Leandro Lucarella <llucax@gmail.com> 2011-11-01 09:50:56 PDT --- OK, then the docs should be more clear I think, is really hard to infer this behavior from the docs (unless someone explains it better :). -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
November 01, 2011 [Issue 6856] Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
Posted in reply to timon.gehr@gmx.ch | http://d.puremagic.com/issues/show_bug.cgi?id=6856 --- Comment #8 from Stewart Gordon <smjg@iname.com> 2011-11-01 10:06:36 PDT --- (In reply to comment #2) > Shouldn't "Y y" print "Y.f()" if Y can loose the in contract? > Shouldn't "X z" and "Y z" print *something* (probably "X.f()" and "Y.f()" > respectively)? Only one of the contracts needs to pass for the overall contract to pass. So once it's tried one and found that it's passed, it doesn't need to try the others. When you have a Y, it first tries X's in contract. This passes, so it doesn't need to check Y's as well. Of course, an implementation could just as well check Y's contract first and then fall back to X's if that fails. But because Z's in contract is empty, the compiler just optimises away the whole contract checking. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
November 02, 2011 [Issue 6856] Preconditions are not inherited | ||||
---|---|---|---|---|
| ||||
Posted in reply to timon.gehr@gmx.ch | http://d.puremagic.com/issues/show_bug.cgi?id=6856 Don <clugdbug@yahoo.com.au> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |clugdbug@yahoo.com.au --- Comment #9 from Don <clugdbug@yahoo.com.au> 2011-11-02 01:30:27 PDT --- (In reply to comment #8) > (In reply to comment #2) > > Shouldn't "Y y" print "Y.f()" if Y can loose the in contract? > > Shouldn't "X z" and "Y z" print *something* (probably "X.f()" and "Y.f()" > > respectively)? > > Only one of the contracts needs to pass for the overall contract to pass. So once it's tried one and found that it's passed, it doesn't need to try the others. > > When you have a Y, it first tries X's in contract. This passes, so it doesn't need to check Y's as well. Of course, an implementation could just as well check Y's contract first and then fall back to X's if that fails. > > But because Z's in contract is empty, the compiler just optimises away the whole contract checking. I'm a little confused by the relationship between this bug and bug 6857. If you accept 6857, then if you call a function f() from a base class B, only the precondition of the base class should matter. Although one derived class C.f() may accept a weaker precondition, the caller doesn't actually know it had a C, so it's making an unwarranted assumption. So, if you accept that, then contracts in derived classes don't matter unless they are called directly. That's really odd, because you have a single function which has two different semantic guarantees depending on who is calling it. Following this through, I don't see the need for explicit widening of preconditions at all. If we didn't have the feature, and you needed it (which I believe happens very rarely), you could just create a separate function g() for the direct calls, and give _it_ the weaker contract. The derived function f() can just call g(). If you need to rely on the weaker contract, call g() instead of f(). Easy to implement, easy to understand. This explicit widening of preconditions of virtual functions seems to be a really niche feature. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- |
Copyright © 1999-2021 by the D Language Foundation