digitalmars.D - Out contracts: how to refer to objects' start state
- Peter Williams (10/10) May 25 2013 For some class methods, to express comprehensive out{} contracts it is
- Andrei Alexandrescu (13/23) May 25 2013 Unfortunately we don't have a solution to that. A while ago I proposed
- Andrej Mitrovic (4/12) May 25 2013 Perhaps we could support this by allowing qualification of the in block:
- Andrei Alexandrescu (10/23) May 25 2013 The problem with this is well-defining it. Since every in.xyz expression...
- Adam D. Ruppe (4/10) May 25 2013 Here, in.oldLen refers to the local variable you defined in the
- Andrei Alexandrescu (4/13) May 25 2013 Ohh, I see. Yes, that could work.
- Peter Williams (3/16) May 25 2013 That revelation also answers my question about how it could break code.
- Idan Arye (16/36) May 27 2013 Wouldn't it be simpler to define in the `in` clause what to pass
- Andrei Alexandrescu (3/18) May 27 2013 I think that got too cute.
- bearophile (5/14) May 25 2013 Then we have to take a look at how C# and Ada solve such problem
- bearophile (10/14) May 25 2013 The "prestate" is an important part of contract programming. So
- Peter Williams (4/28) May 25 2013 How would it break code? I've tried to imagine how but have failed.
- deadalnix (2/5) May 27 2013 Can you expand more on the breakage risk please ?
- Jonathan M Davis (8/14) May 27 2013 If nothing else, it would mean that the variables inside of the in block...
- deadalnix (4/24) May 27 2013 You are right, destructor is an issue. The risk of name collision
- Idan Arye (6/33) May 27 2013 Yet another reason why those variable should be declared as such
- Andrei Alexandrescu (3/16) May 27 2013 Oh, destructors too.
- Andrei Alexandrescu (3/9) May 27 2013 Easy - name collisions between the in and the out blocks.
For some class methods, to express comprehensive out{} contracts it is necessary to be able to refer to the state of the class object before the operation as well as after it e.g. if the method adds something to a container you need to be able to specify that nothing was accidentally deleted from the container during the method. I've scoured the language specification and Andrei's book for advice on how to do this without any luck. Can it be done and, if so, how? Thanks Peter
May 25 2013
On 5/25/13 8:38 PM, Peter Williams wrote:For some class methods, to express comprehensive out{} contracts it is necessary to be able to refer to the state of the class object before the operation as well as after it e.g. if the method adds something to a container you need to be able to specify that nothing was accidentally deleted from the container during the method. I've scoured the language specification and Andrei's book for advice on how to do this without any luck. Can it be done and, if so, how? Thanks PeterUnfortunately we don't have a solution to that. A while ago I proposed that the "in" and "out" contracts share the same scope. That would allow us to do: class A { void fun() in { auto oldLen = this.length; } out { assert(this.length == oldLen + 1); } body { ... } } That was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible. Andrei
May 25 2013
On 5/26/13, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:class A { void fun() in { auto oldLen = this.length; } out { assert(this.length == oldLen + 1); } body { ... } } That was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible.Perhaps we could support this by allowing qualification of the in block: out { assert(this.length == in.oldLen + 1); } "in" is a keyword so it shouldn't break any existing code.
May 25 2013
On 5/25/13 9:03 PM, Andrej Mitrovic wrote:On 5/26/13, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org> wrote:The problem with this is well-defining it. Since every in.xyz expression could access an arbitrary method of the old object, that means the whole object would need to be somehow duplicated. Alternatively, all in.xyz expressions would need to be evaluated before the function's entry point, which is weird (what order? how about side effects? etc). The whole in.xyz trick (or as in Eiffel old.xyz) is inherently flimsy. I'd rather allow the user to save and check their own state instead, without resorting to a complicated definition. Andreiclass A { void fun() in { auto oldLen = this.length; } out { assert(this.length == oldLen + 1); } body { ... } } That was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible.Perhaps we could support this by allowing qualification of the in block: out { assert(this.length == in.oldLen + 1); } "in" is a keyword so it shouldn't break any existing code.
May 25 2013
On Sunday, 26 May 2013 at 01:12:35 UTC, Andrei Alexandrescu wrote:On 5/25/13 9:03 PM, Andrej Mitrovic wrote:On 5/26/13, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>in { auto oldLen = this.length; }out { assert(this.length == in.oldLen + 1); }Since every in.xyz expression could access an arbitrary method of the old object,Here, in.oldLen refers to the local variable you defined in the in{} scope, as opposed to plain oldLen which would be searing the out{} scope.
May 25 2013
On 5/25/13 9:18 PM, Adam D. Ruppe wrote:On Sunday, 26 May 2013 at 01:12:35 UTC, Andrei Alexandrescu wrote:Ohh, I see. Yes, that could work. Thanks, AndreiOn 5/25/13 9:03 PM, Andrej Mitrovic wrote:On 5/26/13, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>in { auto oldLen = this.length; }out { assert(this.length == in.oldLen + 1); }Since every in.xyz expression could access an arbitrary method of the old object,Here, in.oldLen refers to the local variable you defined in the in{} scope, as opposed to plain oldLen which would be searing the out{} scope.
May 25 2013
On 26/05/13 11:47, Andrei Alexandrescu wrote:On 5/25/13 9:18 PM, Adam D. Ruppe wrote:That revelation also answers my question about how it could break code. PeterOn Sunday, 26 May 2013 at 01:12:35 UTC, Andrei Alexandrescu wrote:Ohh, I see. Yes, that could work.On 5/25/13 9:03 PM, Andrej Mitrovic wrote:On 5/26/13, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>in { auto oldLen = this.length; }out { assert(this.length == in.oldLen + 1); }Since every in.xyz expression could access an arbitrary method of the old object,Here, in.oldLen refers to the local variable you defined in the in{} scope, as opposed to plain oldLen which would be searing the out{} scope.
May 25 2013
On Sunday, 26 May 2013 at 01:47:39 UTC, Andrei Alexandrescu wrote:On 5/25/13 9:18 PM, Adam D. Ruppe wrote:Wouldn't it be simpler to define in the `in` clause what to pass to the out clause? Something like: class A { void fun() in { out oldLen = this.length; } out { assert(this.length == oldLen + 1); } body { ... } } Or even combine the two: class A { void fun() in { out oldLen = this.length; } out { assert(this.length == in.oldLen + 1); } body { ... } }On Sunday, 26 May 2013 at 01:12:35 UTC, Andrei Alexandrescu wrote:Ohh, I see. Yes, that could work. Thanks, AndreiOn 5/25/13 9:03 PM, Andrej Mitrovic wrote:On 5/26/13, Andrei Alexandrescu<SeeWebsiteForEmail erdani.org>in { auto oldLen = this.length; }out { assert(this.length == in.oldLen + 1); }Since every in.xyz expression could access an arbitrary method of the old object,Here, in.oldLen refers to the local variable you defined in the in{} scope, as opposed to plain oldLen which would be searing the out{} scope.
May 27 2013
On 5/27/13 3:21 AM, Idan Arye wrote:Wouldn't it be simpler to define in the `in` clause what to pass to the out clause? Something like: class A { void fun() in { out oldLen = this.length; } out { assert(this.length == oldLen + 1); } body { ... } } Or even combine the two: class A { void fun() in { out oldLen = this.length; } out { assert(this.length == in.oldLen + 1); } body { ... } }I think that got too cute. Andrei
May 27 2013
Andrei Alexandrescu:The problem with this is well-defining it. Since every in.xyz expression could access an arbitrary method of the old object, that means the whole object would need to be somehow duplicated. Alternatively, all in.xyz expressions would need to be evaluated before the function's entry point, which is weird (what order? how about side effects? etc). The whole in.xyz trick (or as in Eiffel old.xyz) is inherently flimsy. I'd rather allow the user to save and check their own state instead, without resorting to a complicated definition.(both support the pre-state). Bye, bearophile
May 25 2013
Andrei Alexandrescu:That was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible.The "prestate" is an important part of contract programming. So it's better to look for some other solution to implement it. --------------- Andrej Mitrovic:"in" is a keyword so it shouldn't break any existing code.Usually languages use the word "old" instead of "in" for this purpose. But I think "in" is acceptable. And it's much better than not having the prestate. Bye, bearophile
May 25 2013
On 26/05/13 10:43, Andrei Alexandrescu wrote:On 5/25/13 8:38 PM, Peter Williams wrote:That looks like a good solution to me.For some class methods, to express comprehensive out{} contracts it is necessary to be able to refer to the state of the class object before the operation as well as after it e.g. if the method adds something to a container you need to be able to specify that nothing was accidentally deleted from the container during the method. I've scoured the language specification and Andrei's book for advice on how to do this without any luck. Can it be done and, if so, how? Thanks PeterUnfortunately we don't have a solution to that. A while ago I proposed that the "in" and "out" contracts share the same scope. That would allow us to do: class A { void fun() in { auto oldLen = this.length; } out { assert(this.length == oldLen + 1); } body { ... } } That was technically difficult to do back then, and fell by the wayside.Today it would break too much code to introduce even if feasible.How would it break code? I've tried to imagine how but have failed. Peter
May 25 2013
On Sunday, 26 May 2013 at 00:43:36 UTC, Andrei Alexandrescu wrote:That was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible.Can you expand more on the breakage risk please ?
May 27 2013
On Monday, May 27, 2013 09:37:38 deadalnix wrote:On Sunday, 26 May 2013 at 00:43:36 UTC, Andrei Alexandrescu wrote:If nothing else, it would mean that the variables inside of the in block would not go out of scope when the in block ended, so their destructors would not be called and the like, whereas now they would be. The same goes for scope statements in the in block. I don't know how much of an issue any of that is realistically though. But Andrei may have other reasons why it would be a problem. - Jonathan M DavisThat was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible.Can you expand more on the breakage risk please ?
May 27 2013
On Monday, 27 May 2013 at 07:42:44 UTC, Jonathan M Davis wrote:On Monday, May 27, 2013 09:37:38 deadalnix wrote:You are right, destructor is an issue. The risk of name collision exists as well but I don't think it is realistically that widespread in actual codebase.On Sunday, 26 May 2013 at 00:43:36 UTC, Andrei Alexandrescu wrote:If nothing else, it would mean that the variables inside of the in block would not go out of scope when the in block ended, so their destructors would not be called and the like, whereas now they would be. The same goes for scope statements in the in block. I don't know how much of an issue any of that is realistically though. But Andrei may have other reasons why it would be a problem.That was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible.Can you expand more on the breakage risk please ?
May 27 2013
On Monday, 27 May 2013 at 09:06:58 UTC, deadalnix wrote:On Monday, 27 May 2013 at 07:42:44 UTC, Jonathan M Davis wrote:Yet another reason why those variable should be declared as such in the `in` clause. Variables declared in the `in` clause using the `out` attribute would have their destruction done after the `out` clause, and all other variables declared in the `in` clause would be destructed after the `in` clause.On Monday, May 27, 2013 09:37:38 deadalnix wrote:You are right, destructor is an issue. The risk of name collision exists as well but I don't think it is realistically that widespread in actual codebase.On Sunday, 26 May 2013 at 00:43:36 UTC, Andrei Alexandrescu wrote:If nothing else, it would mean that the variables inside of the in block would not go out of scope when the in block ended, so their destructors would not be called and the like, whereas now they would be. The same goes for scope statements in the in block. I don't know how much of an issue any of that is realistically though. But Andrei may have other reasons why it would be a problem.That was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible.Can you expand more on the breakage risk please ?
May 27 2013
On 5/27/13 3:42 AM, Jonathan M Davis wrote:On Monday, May 27, 2013 09:37:38 deadalnix wrote:Oh, destructors too. AndreiOn Sunday, 26 May 2013 at 00:43:36 UTC, Andrei Alexandrescu wrote:If nothing else, it would mean that the variables inside of the in block would not go out of scope when the in block ended, so their destructors would not be called and the like, whereas now they would be. The same goes for scope statements in the in block. I don't know how much of an issue any of that is realistically though. But Andrei may have other reasons why it would be a problem.That was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible.Can you expand more on the breakage risk please ?
May 27 2013
On 5/27/13 3:37 AM, deadalnix wrote:On Sunday, 26 May 2013 at 00:43:36 UTC, Andrei Alexandrescu wrote:Easy - name collisions between the in and the out blocks. AndreiThat was technically difficult to do back then, and fell by the wayside. Today it would break too much code to introduce even if feasible.Can you expand more on the breakage risk please ?
May 27 2013