Design by contracts and constructors

青春壹個敷衍的年華 提交于 2019-11-29 06:30:46

I completely disagree with Thomas's answer. As long as you are making choices in the implementation of ArrayList(), you should have a contract for it that document these choices.

Here, you are making the choice of calling the main constructor with argument 32. There are many other things that you could have decided to do (not just concerning the choice of the default size). Giving a contract to ArrayList() that is almost identical to that of ArrayList(int) documents that you decided not to do most of the silly things you could have done instead of calling it directly.

The answer "it calls the main constructor, so let the main constructor's contract do the job" completely ignores the fact that the contract is there to save you from having to look at the implementation. For a verification strategy based on run-time assertion checking, the disadvantage of writing contracts even for such short constructors/methods that almost directly call another constructor/method is that you end up checking things twice. Yes, it seems redundant, but run-time assertion checking is only one verification strategy, and DbC's principles are independent from it. The principle is: if it can be called, it needs a contract to document what it does.

porges

Client code (using Code Contracts) that uses ArrayList won't know that the empty constructor Ensures that Size == 32 unless you explicitly state so using an Ensure.

So (for example):

var x = new ArrayList();
Contract.Assert(x.Size == 32)

will give you the warning "assert not proven".

You need to explicitly state all contracts; the code contracts rewriter/static checker won't "look through" a method to see any implications — see my answer to the related question "Do we have to specify Contract.Requires(…) statements redundantly in delegating methods?"

I recommend reading Object Oriented Software Construction, 2nd Edition, or maybe Touch of Class, both from Bertrand Meyer. Alternatively, you could read the 1992 article Applying "Design by Contract" from the same author.

To summarize:

  • The class invariant must hold after the constructor (any of them) finishes, and before and after any public method of the class is executed.
  • Method preconditions and postconditions are additional conditions which must hold on entering and exiting any public method, along with the invariant.

So in your case, focus in the invariant. Produce a correct object (one which satisfies the class invariant), no matter which constructor is invoked.

In this related answer I discussed similar topics, including an example.

Umh, I don't fully understand why you put the 'Ensures' also in the default c'tor. Because it calls the main c'tor, which already does implement the full contract, the default c'tor does that as well - by definition. So this is a logical redundancy, and therefore a big 'Don't'. Maybe it could have pragmatic implications, like you say - don't know Code Contracts that good...

Regarding literature - the best sources are:

HTH! Thomas

Design by contract comes from the mathematical roots of functional programming: Preconditions and Postconditions.

You don't really need a book on it, it's at most a chapter of a Computer Science degree (most will teach the concept). The basic premise is you write the preconditions that the function expects and the output it will produce given the correct parameters. The function will not be expected to work with incorrect initial parameters. The same can be said for an algorithm: it's infallible, that is it's guaranteed to provide the expected result.

That's how I've been taught it in the degree I'm currently studying, there may be better definitions around though. The Wikipedia article on Design by contract is written with an OO slant, but pre/postconditions are language independent.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!