www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - An old topic (pun intended)

reply Davidson Corry <davidsoncorry comcast.net> writes:
Did D2 ever implement the Eiffel "old" construct? I do not see it 
mentioned in "The D Programming Language", and the only reference I can 
find in the newsgroup is a short discussion in June of 2007 that seemed 
to go nowhere.

If not, has anyone developed a reasonable workaround? Thanks.

-- Davidson

  ============

Brief description: in Eiffel,
       old expr
can be used in post-conditions, and evaluates to the value of
       expr
as of entry to the function. It's useful to help verify that the 
function has done what it was supposed to, but especially powerful when 
used in classes because it complements invariant:  invariant tests what 
has *not* varied (duh),    old expr   helps test what *has* varied to 
ensure that it has varied *correctly*.

For example, the .Add() method of a Container class might in its 
postcondition assert
        assert( count == old count + 1 )
to ensure that *exactly* one element got added, no more and no less
Oct 12 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Davidson Corry:

 Did D2 ever implement the Eiffel "old" construct?

At the moment there no prestate in D. I agree that prestate is an important sub-feature of contract programming. It was discussed two or three times, but the discussions didn't produce actual results. I think it was not implemented because I think Walter thinks D contract programming is a half failure (I don't agree on this) and because implementing the prestate is a bit tricky. I suggest to ask about this in the main D newsgroup, and show two use cases too. I think if enough people show use cases, and someone writes a good enough pull request for DMD, it will be added to D/DMD.
 If not, has anyone developed a reasonable workaround? Thanks.

In classes inside a debug I have defined handmade "ghost attributes": debug { int ghost1, ghost2; } I use them to manually store the prestate that later I want to verify. This is not a very good solution... Bye, bearophile
Oct 13 2011
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, October 13, 2011 05:35:52 bearophile wrote:
 Davidson Corry:
 Did D2 ever implement the Eiffel "old" construct?

At the moment there no prestate in D. I agree that prestate is an important sub-feature of contract programming. It was discussed two or three times, but the discussions didn't produce actual results. I think it was not implemented because I think Walter thinks D contract programming is a half failure (I don't agree on this) and because implementing the prestate is a bit tricky.

I don't recall him ever saying anything about contract programming in D being a failure in any way. IIRC, old was rejected because it added extra complication for little value. - Jonathan M Davis
Oct 13 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 I don't recall him ever saying anything about contract programming in D being 
 a failure in any way.

He said unittesting has changed the why you write code and has significantly decreased bugs count, while he was not equally happy about contract programming. From several things he has said, he looks disappointed by D contract programming.
 IIRC, old was rejected because it added extra 
 complication for little value.

It add some complexity, but I can't agree that it adds little value, this is a mistake. The prestate increases significantly the usefulness of contract programming. And I don't remember it being rejected, I just remember the discussion stopped, like a river dying and drying up in a desert. Do you have a link of a post where it was rejected? I think there is an enhancement request about prestate in Bugzilla, and it is open still. Before actually rejecting this feature, it will need one more good discussion in the main D newsgroup. ---------------------- Ali Çehreli:
 He had mentioned that at some point the implementation of contract
 programming had serious bugs but nobody had complained.

I am not sure, but I think I did complain about some of those bugs. I have some old bug reports in Bugzilla about contract programming that are open still. Bye, bearophile
Oct 13 2011
next sibling parent reply Davidson Corry <davidsoncorry comcast.net> writes:
On 10/13/2011 10:57 AM, bearophile wrote:
 Jonathan M Davis:

 I don't recall him ever saying anything about contract programming in D being
a failure in any way.

He said unittesting has changed the way you write code and has significantly decreased bugs count, while he was not equally happy about contract programming. From several things he has said, he looks disappointed by D contract programming.
 IIRC, old was rejected because it added extra complication for little value.

It add some complexity, but I can't agree that it adds little value... And I don't remember it being rejected, I just remember the discussion stopped, like a river dying and drying up in a desert.

Implementing DbC is tricky, and 'old' particularly so. For instance, what if the condition whose state-at-entry you want to inspect at exit happens to reside in a base class implemented in a different module? (Note that D supports separate compilation while Eiffel doesn't.) 'unittest' is a major win in D, and may as a practical matter alleviate much of the need for other kinds of testing. But... [opinion] ...unit testing and DbC are *orthogonal* or at least complementary, in my view. Conceptually, unit testing tests a class or object from the *outside* of its public boundaries, while DbC tests the object from *within*. They catch different classes (sic) of implementation error. Some bugs may be caught both ways, which is great. But some might slip by one, only to be caught by the other. Like any technique (including unit testing) DbC takes practice to learn how to do well, and it is new to most programmers even 25 years after Meyer brought it to the masses. There's a bootstrapping problem here: if DbC isn't fully implemented, it's not as useful. If it's not useful, programmers won't use it. If they don't use it, compiler implementers won't improve the implementation. And so on. Look, Walters are in scarce supply, and I don't want to jog their elbows on priorities -- they come up with so much other cool stuff! I'm just saying, 'old' would be nice. [/opinion] -- Davidson
Oct 13 2011
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/13/2011 08:25 PM, Davidson Corry wrote:
 On 10/13/2011 10:57 AM, bearophile wrote:
 Jonathan M Davis:

 I don't recall him ever saying anything about contract programming in
 D being a failure in any way.

He said unittesting has changed the way you write code and has significantly decreased bugs count, while he was not equally happy about contract programming. From several things he has said, he looks disappointed by D contract programming.
 IIRC, old was rejected because it added extra complication for little
 value.

It add some complexity, but I can't agree that it adds little value... And I don't remember it being rejected, I just remember the discussion stopped, like a river dying and drying up in a desert.

Implementing DbC is tricky, and 'old' particularly so. For instance, what if the condition whose state-at-entry you want to inspect at exit happens to reside in a base class implemented in a different module? (Note that D supports separate compilation while Eiffel doesn't.) 'unittest' is a major win in D, and may as a practical matter alleviate much of the need for other kinds of testing. But... [opinion] ...unit testing and DbC are *orthogonal* or at least complementary, in my view. Conceptually, unit testing tests a class or object from the *outside* of its public boundaries, while DbC tests the object from *within*. They catch different classes (sic) of implementation error. Some bugs may be caught both ways, which is great. But some might slip by one, only to be caught by the other. Like any technique (including unit testing) DbC takes practice to learn how to do well, and it is new to most programmers even 25 years after Meyer brought it to the masses. There's a bootstrapping problem here: if DbC isn't fully implemented, it's not as useful. If it's not useful, programmers won't use it. If they don't use it, compiler implementers won't improve the implementation. And so on. Look, Walters are in scarce supply, and I don't want to jog their elbows on priorities -- they come up with so much other cool stuff! I'm just saying, 'old' would be nice. [/opinion] -- Davidson

I don't agree that 'old' is very difficult to implement. Just evaluate what is inside the 'old' before you enter the in contract, store somewhere, maybe in hidden local variables, and make the data available in the out contract. Eiffel's 'old' does not do more than that. (but perhaps there are implementation details in DMD that make this more difficult than necessary. I don't know.)
Oct 16 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 10/16/2011 07:31 PM, Jonathan M Davis wrote:
 On Sunday, October 16, 2011 19:13:09 Timon Gehr wrote:
 I don't agree that 'old' is very difficult to implement. Just evaluate
 what is inside the 'old' before you enter the in contract, store
 somewhere, maybe in hidden local variables, and make the data available
 in the out contract. Eiffel's 'old' does not do more than that.

 (but perhaps there are implementation details in DMD that make this more
 difficult than necessary. I don't know.)

What if you're dealing with a class? You'd need to deep copy the entire object for it to work. There's no way built into the language to do that (not to mention that it would be horrifically inefficient). - Jonathan M Davis

Eiffel does not do that either. (even though it _does_ have a built in deep copy feature) We don't have to over-engineer the feature, if somebody needs to deep-copy an object they can implement it themselves and use old(obj.deepCopy()).
Oct 16 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 Eiffel does not do that either.
 (even though it _does_ have a built in deep copy feature)
 
 We don't have to over-engineer the feature, if somebody needs to 
 deep-copy an object they can implement it themselves and use 
 old(obj.deepCopy()).

I agree. A shallow prestate is quite better than not having it at all in D. Lately C# has implemented DbC, prestate too. I don't know how, but it's worth taking a look. Bye, bearophile
Oct 16 2011
parent reply =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= <xtzgzorex gmail.com> writes:
On 17-10-2011 02:43, bearophile wrote:
 Timon Gehr:

 Eiffel does not do that either.
 (even though it _does_ have a built in deep copy feature)

 We don't have to over-engineer the feature, if somebody needs to
 deep-copy an object they can implement it themselves and use
 old(obj.deepCopy()).

I agree. A shallow prestate is quite better than not having it at all in D. Lately C# has implemented DbC, prestate too. I don't know how, but it's worth taking a look. Bye, bearophile

Just for the record, the documentation is at: http://download.microsoft.com/download/C/2/7/C2715F76-F56C-4D37-9231-EF8076B7EC13/userdoc.pdf I agree that having old would be great, even if without deep copying (which is probably a terrible idea anyway). Also note that C# doesn't do deep copying here. - Alex
Oct 16 2011
parent reply Davidson Corry <davidsoncorry comcast.net> writes:
On 10/16/2011 9:35 PM, Alex Rønne Petersen wrote:
 On 17-10-2011 02:43, bearophile wrote:
 Timon Gehr:

 Eiffel does not do that either.
 (even though it _does_ have a built in deep copy feature)

 We don't have to over-engineer the feature, if somebody needs to
 deep-copy an object they can implement it themselves and use
 old(obj.deepCopy()).

I agree. A shallow prestate is quite better than not having it at all in D. Lately C# has implemented DbC, prestate too. I don't know how, but it's worth taking a look. Bye, bearophile

Just for the record, the documentation is at: http://download.microsoft.com/download/C/2/7/C2715F76-F56C-4D37-9231-EF8076B7EC13/userdoc.pdf I agree that having old would be great, even if without deep copying (which is probably a terrible idea anyway). Also note that C# doesn't do deep copying here. - Alex

Remember, efficiency is not the point, correctness is. Contract code goes away in the release build. (Arguably you might want to keep *preconditions* in library code, since they vet your input parameters. But in practice those usually go away in release builds as well, even in Eiffel.) -- Dai
Oct 16 2011
parent =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= <xtzgzorex gmail.com> writes:
On 17-10-2011 07:59, Davidson Corry wrote:
 On 10/16/2011 9:35 PM, Alex Rønne Petersen wrote:
 On 17-10-2011 02:43, bearophile wrote:
 Timon Gehr:

 Eiffel does not do that either.
 (even though it _does_ have a built in deep copy feature)

 We don't have to over-engineer the feature, if somebody needs to
 deep-copy an object they can implement it themselves and use
 old(obj.deepCopy()).

I agree. A shallow prestate is quite better than not having it at all in D. Lately C# has implemented DbC, prestate too. I don't know how, but it's worth taking a look. Bye, bearophile

Just for the record, the documentation is at: http://download.microsoft.com/download/C/2/7/C2715F76-F56C-4D37-9231-EF8076B7EC13/userdoc.pdf I agree that having old would be great, even if without deep copying (which is probably a terrible idea anyway). Also note that C# doesn't do deep copying here. - Alex

Remember, efficiency is not the point, correctness is. Contract code goes away in the release build. (Arguably you might want to keep *preconditions* in library code, since they vet your input parameters. But in practice those usually go away in release builds as well, even in Eiffel.) -- Dai

Right, but you don't want your debug builds to be so slow that it makes you unproductive either. Either way, an initial lightweight old() would already be much better than having nothing. :) - Alex
Oct 17 2011
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/17/2011 08:04 AM, Jonathan M Davis wrote:
 On Monday, October 17, 2011 00:29:30 Timon Gehr wrote:
 On 10/16/2011 07:31 PM, Jonathan M Davis wrote:
 On Sunday, October 16, 2011 19:13:09 Timon Gehr wrote:
 I don't agree that 'old' is very difficult to implement. Just evaluate
 what is inside the 'old' before you enter the in contract, store
 somewhere, maybe in hidden local variables, and make the data
 available
 in the out contract. Eiffel's 'old' does not do more than that.

 (but perhaps there are implementation details in DMD that make this
 more
 difficult than necessary. I don't know.)

What if you're dealing with a class? You'd need to deep copy the entire object for it to work. There's no way built into the language to do that (not to mention that it would be horrifically inefficient). - Jonathan M Davis

Eiffel does not do that either. (even though it _does_ have a built in deep copy feature) We don't have to over-engineer the feature, if somebody needs to deep-copy an object they can implement it themselves and use old(obj.deepCopy()).

I don't see how you could really expect to test the current state against the initial state when you don't actually save the initial state.

There are practical examples where this would be required but most of the time the tests are simple enough that the old expression can carry all the state you need. Remember that all implementations of DbC that have prestate (and I am aware of) don't perform a deep copy automatically. Eg: abstract class Set{ property int size(); bool contains(int x); void insert(int x) out{ assert( old(contains(x)) && size == old(size) || !old(contains(x)) && size == old(size)+1); assert(contains(old(x))); // possibly also require that everything that was // in the set before is still there [...] } }
 And as far as
 implementing it yourself goes, you could go and do that that right now. You
 don't need compiler support to save the initial state somewhere and then test
 against it afterwards. It's just nicer if the compiler gives you support for
 it.

 - Jonathan M Davis

As far as implementing it myself goes I could even do contract programming in the brainF programming language. =) The feature adds a lot of value to contract programming. I use contract programming occasionally and almost every contract I add eventually detects small bugs during the testing of new code parts. BTW: "Somewhere" would have to be on the execution stack because the function could be recursive. There is no way to refer to variables defined in the in contract from the out contract and doing the saving at any other place than in a contract is not acceptable for obvious reasons.
Oct 17 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, October 16, 2011 19:13:09 Timon Gehr wrote: 
 I don't agree that 'old' is very difficult to implement. Just evaluate
 what is inside the 'old' before you enter the in contract, store
 somewhere, maybe in hidden local variables, and make the data available
 in the out contract. Eiffel's 'old' does not do more than that.
 
 (but perhaps there are implementation details in DMD that make this more
 difficult than necessary. I don't know.)

What if you're dealing with a class? You'd need to deep copy the entire object for it to work. There's no way built into the language to do that (not to mention that it would be horrifically inefficient). - Jonathan M Davis
Oct 16 2011
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 I'd have to go digging, but from what I recall, it was pretty clear that it 
 wasn't happening.

I see. And sorry for the tone of my last answer. Don't worry if you don't have the time to find it. Bye, bearophile
Oct 13 2011
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 10/13/2011 07:14 PM, Ali Çehreli wrote:
 On Thu, 13 Oct 2011 09:18:46 -0700, Jonathan M Davis wrote:

 On Thursday, October 13, 2011 05:35:52 bearophile wrote:
 Davidson Corry:
 Did D2 ever implement the Eiffel "old" construct?

At the moment there no prestate in D. I agree that prestate is an important sub-feature of contract programming. It was discussed two or three times, but the discussions didn't produce actual results. I think it was not implemented because I think Walter thinks D contract programming is a half failure (I don't agree on this) and because implementing the prestate is a bit tricky.

I don't recall him ever saying anything about contract programming in D being a failure in any way.

He had mentioned that at some point the implementation of contract programming had serious bugs but nobody had complained.
 IIRC, old was rejected because it added
 extra complication for little value.

Yes, there were technical difficulties in making the stack frame at the call point available to the stack frame at the exit point.

Why would that be required?
Oct 16 2011
prev sibling next sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Thu, 13 Oct 2011 09:18:46 -0700, Jonathan M Davis wrote:

 On Thursday, October 13, 2011 05:35:52 bearophile wrote:
 Davidson Corry:
 Did D2 ever implement the Eiffel "old" construct?

At the moment there no prestate in D. I agree that prestate is an important sub-feature of contract programming. It was discussed two or three times, but the discussions didn't produce actual results. I think it was not implemented because I think Walter thinks D contract programming is a half failure (I don't agree on this) and because implementing the prestate is a bit tricky.

I don't recall him ever saying anything about contract programming in D being a failure in any way.

He had mentioned that at some point the implementation of contract programming had serious bugs but nobody had complained.
 IIRC, old was rejected because it added
 extra complication for little value.

Yes, there were technical difficulties in making the stack frame at the call point available to the stack frame at the exit point.
 
 - Jonathan M Davis

Ali
Oct 13 2011
prev sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Sun, 16 Oct 2011 19:09:46 +0200, Timon Gehr wrote:

 On 10/13/2011 07:14 PM, Ali Çehreli wrote:
 On Thu, 13 Oct 2011 09:18:46 -0700, Jonathan M Davis wrote:
 IIRC, old was rejected because it added extra complication for little
 value.

Yes, there were technical difficulties in making the stack frame at the call point available to the stack frame at the exit point.


I am not sure myself. I find this thread where Andrei says "Walter tried to implement that but it turned out to be very difficult implementation- wise": http://www.digitalmars.com/d/archives/digitalmars/D/ Communicating_between_in_and_out_contracts_98252.html Ali
Oct 17 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, October 13, 2011 10:57 bearophile wrote:
 Jonathan M Davis:
 IIRC, old was rejected because it added extra
 complication for little value.

It add some complexity, but I can't agree that it adds little value, this is a mistake. The prestate increases significantly the usefulness of contract programming. And I don't remember it being rejected, I just remember the discussion stopped, like a river dying and drying up in a desert. Do you have a link of a post where it was rejected? I think there is an enhancement request about prestate in Bugzilla, and it is open still. Before actually rejecting this feature, it will need one more good discussion in the main D newsgroup.

I'd have to go digging, but from what I recall, it was pretty clear that it wasn't happening. But since it's not a feature that I care about at all, it's not something that I've tracked particularly closely. - Jonathan M Davis
Oct 13 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, October 17, 2011 00:29:30 Timon Gehr wrote:
 On 10/16/2011 07:31 PM, Jonathan M Davis wrote:
 On Sunday, October 16, 2011 19:13:09 Timon Gehr wrote:
 I don't agree that 'old' is very difficult to implement. Just evaluate
 what is inside the 'old' before you enter the in contract, store
 somewhere, maybe in hidden local variables, and make the data
 available
 in the out contract. Eiffel's 'old' does not do more than that.
 
 (but perhaps there are implementation details in DMD that make this
 more
 difficult than necessary. I don't know.)

What if you're dealing with a class? You'd need to deep copy the entire object for it to work. There's no way built into the language to do that (not to mention that it would be horrifically inefficient). - Jonathan M Davis

Eiffel does not do that either. (even though it _does_ have a built in deep copy feature) We don't have to over-engineer the feature, if somebody needs to deep-copy an object they can implement it themselves and use old(obj.deepCopy()).

I don't see how you could really expect to test the current state against the initial state when you don't actually save the initial state. And as far as implementing it yourself goes, you could go and do that that right now. You don't need compiler support to save the initial state somewhere and then test against it afterwards. It's just nicer if the compiler gives you support for it. - Jonathan M Davis
Oct 16 2011