mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2025-12-07 15:22:31 +01:00
Author:halw
Date:2008-12-16T02:27:18.000000Z git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@140 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
@@ -23,80 +23,80 @@ Design by Contract (DbC) begins as an implementation of some of the ideas from f
|
||||
|
||||
Design by Contract is built around a model for software correctness that is really pretty simple.
|
||||
|
||||
Suppose there is software routine called <code> s </code>. If we were going to test <code> s </code>, we would probably devise some test inputs or test values to be in place when <code> s </code> starts and then observe what things look like after <code> s </code> completes. If they look the way we think they should then that leads us to believe that S is working correctly for those test inputs.
|
||||
Suppose there is software routine called <code>s</code>. If we were going to test <code>s</code>, we would probably devise some test inputs or test values to be in place when <code>s</code> starts and then observe what things look like after <code>s</code> completes. If they look the way we think they should then that leads us to believe that S is working correctly for those test inputs.
|
||||
|
||||
We can generalize and formalize that process a bit, taking it back from testing an into design. If indeed we know what it means for <code> s </code> to be correct, then we should be able to make a statement of any conditions that must be true prior to executing <code> s </code>. That is, we will state the conditions required for it to be possible for <code> s </code> to run correctly. We call this statement of preconditions for success <code> s </code>'s precondition.
|
||||
We can generalize and formalize that process a bit, taking it back from testing an into design. If indeed we know what it means for <code>s</code> to be correct, then we should be able to make a statement of any conditions that must be true prior to executing <code>s</code>. That is, we will state the conditions required for it to be possible for <code>s</code> to run correctly. We call this statement of preconditions for success <code>s</code>'s precondition.
|
||||
|
||||
Likewise we should be able to make a statement of the conditions that will be true always if <code> s </code> works correctly. This we call <code> s </code>'s postcondition.
|
||||
Likewise we should be able to make a statement of the conditions that will be true always if <code>s</code> works correctly. This we call <code>s</code>'s postcondition.
|
||||
|
||||
As an example, suppose <code> s </code> accepted an argument of type <code> REAL </code> and returned another <code> REAL </code> which was the square root of the argument. The precondition for <code> s </code> would be that the argument could not be less that zero, as there is no real square root for negative numbers. <code> s </code>'s postcondition would be that the result multiplied by itself would yield the value of the original argument (give or take a little to allow for floating point error).
|
||||
As an example, suppose <code>s</code> accepted an argument of type <code>REAL</code> and returned another <code>REAL</code> which was the square root of the argument. The precondition for <code>s</code> would be that the argument could not be less that zero, as there is no real square root for negative numbers. <code>s</code>'s postcondition would be that the result multiplied by itself would yield the value of the original argument (give or take a little to allow for floating point error).
|
||||
|
||||
==Assertions in Eiffel==
|
||||
|
||||
Each Eiffel feature which is a routine, i.e. a function or procedure, can support one assertion for a precondition and one for a postcondition. We saw where precondition and postcondition fit into the structure of the routine in [[Adding Class Features|Adding Class Features]] . An assertion is expressed as one or more assertion clauses which are logically <code> and </code>-ed together to produce the assertion. Assertions clauses are boolean expressions that evaluate to true or false.
|
||||
Each Eiffel feature which is a routine, i.e. a function or procedure, can support one assertion for a precondition and one for a postcondition. We saw where precondition and postcondition fit into the structure of the routine in [[Adding Class Features|Adding Class Features]] . An assertion is expressed as one or more assertion clauses which are logically <code>and</code>-ed together to produce the assertion. Assertions clauses are boolean expressions that evaluate to true or false.
|
||||
|
||||
Let's look at another example. Assume you need to produce a class to model a time of day. Each instance of <code> TIME_OF_DAY </code> would hold some particular time of day accurate to the second between 00:00:00 and 23:59:59 inclusive.
|
||||
Let's look at another example. Assume you need to produce a class to model a time of day. Each instance of <code>TIME_OF_DAY</code> would hold some particular time of day accurate to the second between 00:00:00 and 23:59:59 inclusive.
|
||||
|
||||
As a producer, you would be faced with a decision concerning how to maintain the time internally in each instance. For the purpose of our example, let us consider two alternatives:
|
||||
# Keep three instance of <code> INTEGER </code>. One each for hour, minute, and second.
|
||||
# Keep one instance of <code> INTEGER </code> representing the time of day as the number of seconds since 00:00:00.
|
||||
# Keep three instance of <code>INTEGER</code>. One each for hour, minute, and second.
|
||||
# Keep one instance of <code>INTEGER</code> representing the time of day as the number of seconds since 00:00:00.
|
||||
|
||||
This would be an implementation issue for the producer, because it would not affect the services that <code> TIME_OF_DAY </code> could offer clients. If we have a query called <code> minute </code> the first alternative allows us simply to provide the value from storage. Whereas the second alternative will likely cause us to compute <code> minute </code> each time it is requested. But the service looks and works the same for the client in either alternative.
|
||||
This would be an implementation issue for the producer, because it would not affect the services that <code>TIME_OF_DAY</code> could offer clients. If we have a query called <code>minute</code> the first alternative allows us simply to provide the value from storage. Whereas the second alternative will likely cause us to compute <code>minute</code> each time it is requested. But the service looks and works the same for the client in either alternative.
|
||||
|
||||
For now let us assume that we are using the first design alternative. In that case we would code class features for <code> hour </code>, <code> minute </code>, and <code> second </code>.
|
||||
For now let us assume that we are using the first design alternative. In that case we would code class features for <code>hour</code>, <code>minute</code>, and <code>second</code>.
|
||||
<code>
|
||||
feature -- Access
|
||||
|
||||
hour: INTEGER
|
||||
-- Hour expressed as 24-hour value
|
||||
hour: INTEGER
|
||||
-- Hour expressed as 24-hour value
|
||||
|
||||
minute: INTEGER
|
||||
-- Minutes past the hour
|
||||
minute: INTEGER
|
||||
-- Minutes past the hour
|
||||
|
||||
second: INTEGER
|
||||
-- Seconds past the minute
|
||||
second: INTEGER
|
||||
-- Seconds past the minute
|
||||
</code>
|
||||
|
||||
Below is the code for a procedure <code> set_second </code> which receives an argument of type <code> INTEGER </code> and sets the value of the <code> second </code> feature to the argurment.
|
||||
Below is the code for a procedure <code>set_second</code> which receives an argument of type <code>INTEGER</code> and sets the value of the <code>second</code> feature to the argurment.
|
||||
<code>
|
||||
set_second (s: INTEGER) is
|
||||
-- Set the second from `s'
|
||||
do
|
||||
second := s
|
||||
end
|
||||
set_second (s: INTEGER)
|
||||
-- Set the second from `s'.
|
||||
do
|
||||
second := s
|
||||
end
|
||||
</code>
|
||||
|
||||
The routine is simple enough, but there is a problem with it. Suppose a client calls <code> set_second </code> with an argument whose value is invalid, say 3574. Our routine would just stuff this value into <code> second </code> and we would end up with an instance of <code> TIME_OF_DAY </code> which is invalid. In the days before Design by Contract, as soon as we recognized that this problem exists, we would go into "defensive programming" mode and code some " <code> if </code>" statements inside the routine to validate the argument, before acting.
|
||||
The routine is simple enough, but there is a problem with it. Suppose a client calls <code>set_second</code> with an argument whose value is invalid, say 3574. Our routine would just stuff this value into <code>second</code> and we would end up with an instance of <code>TIME_OF_DAY</code> which is invalid. In the days before Design by Contract, as soon as we recognized that this problem exists, we would go into "defensive programming" mode and code some "<code>if</code>" statements inside the routine to validate the argument, before acting.
|
||||
|
||||
Consider though what we can do with Design by Contract. We will add a precondition assertion to <code> set_second </code> that expresses the need for valid arguments.
|
||||
Consider though what we can do with Design by Contract. We will add a precondition assertion to <code>set_second</code> that expresses the need for valid arguments.
|
||||
<code>
|
||||
set_second (s: INTEGER) is
|
||||
-- Set the second from `s'
|
||||
require
|
||||
valid_argument_for_second: 0 <= s and s <= 59
|
||||
do
|
||||
second := s
|
||||
end
|
||||
set_second (s: INTEGER)
|
||||
-- Set the second from `s'.
|
||||
require
|
||||
valid_argument_for_second: 0 <= s and s <= 59
|
||||
do
|
||||
second := s
|
||||
end
|
||||
</code>
|
||||
|
||||
The precondition is introduced by the keyword " <code> require </code>". The text " <code> valid_argument_for_second </code>" is the label for the assertion clause. The boolean expression "0 <= <code> s </code> and <code> s </code> <= 59" says that a good value for <code> s </code> will be between 0 and 59 inclusive.
|
||||
The precondition is introduced by the keyword "<code>require</code>". The text "<code>valid_argument_for_second</code>" is the label for the assertion clause. The boolean expression "<code>0 <= s and s <= 59</code>" says that a good value for <code>s</code> will be between 0 and 59 inclusive.
|
||||
|
||||
Remember that the precondition specifies those things that must be true if <code> set_second </code> has a chance of working correctly. As such, upon execution, the body of this routine will never be executed if an attempt is made to call it in a state that does not meet its precondition. Instead, the caller will incur a precondition violation exception. We will investigate more about what exceptions mean further in [[Exception Mechanism|Exception Mechanism]] .
|
||||
Remember that the precondition specifies those things that must be true if <code>set_second</code> has a chance of working correctly. As such, upon execution, the body of this routine will never be executed if an attempt is made to call it in a state that does not meet its precondition. Instead, the caller will incur a precondition violation exception. We will investigate more about what exceptions mean further in [[Exception Mechanism|Exception Mechanism]] .
|
||||
|
||||
So, what about a postcondition? We noted earlier that a postcondition should make a statement of what will be true in the case that the routine does its work correctly. For <code> set_second </code> this means that after it finishes, the query <code> second </code> should have the same value as the argument that was received from the caller. Below is the feature with the postcondition added.
|
||||
So, what about a postcondition? We noted earlier that a postcondition should make a statement of what will be true in the case that the routine does its work correctly. For <code>set_second</code> this means that after it finishes, the query <code>second</code> should have the same value as the argument that was received from the caller. Below is the feature with the postcondition added.
|
||||
<code>
|
||||
set_second (s: INTEGER) is
|
||||
-- Set the second from `s'
|
||||
require
|
||||
valid_argument_for_second: 0 <= s and s <= 59
|
||||
do
|
||||
second := s
|
||||
ensure
|
||||
second_set: second = s
|
||||
end
|
||||
set_second (s: INTEGER)
|
||||
-- Set the second from `s'.
|
||||
require
|
||||
valid_argument_for_second: 0 <= s and s <= 59
|
||||
do
|
||||
second := s
|
||||
ensure
|
||||
second_set: second = s
|
||||
end
|
||||
</code>
|
||||
|
||||
The postcondition is introduced by the keyword " <code> ensure </code>". Here the expression " <code> second </code> = <code> s </code>" makes certain that the routine did actually do the necessary work to ensure that the value of <code> second </code> matches the value of the argument received.
|
||||
The postcondition is introduced by the keyword "<code>ensure</code>". Here the expression "<code>second = s</code>" makes certain that the routine did actually do the necessary work to ensure that the value of <code>second</code> matches the value of the argument received.
|
||||
|
||||
As you look at the postcondition, you may be tempted to think that the one-line body of the routine is so simple as to make the postconditon unnecessary. To answer this concern we need to look again for a moment at software specification.
|
||||
|
||||
@@ -104,38 +104,38 @@ As you look at the postcondition, you may be tempted to think that the one-line
|
||||
|
||||
If we remove the instructions from a routine and leave its signature, header comment and assertions, we have a specification for the routine.
|
||||
<code>
|
||||
set_second (s: INTEGER) is
|
||||
-- Set the second from `s'
|
||||
require
|
||||
valid_argument_for_second: 0 <= s and s <= 59
|
||||
ensure
|
||||
second_set: second = s
|
||||
end
|
||||
set_second (s: INTEGER)
|
||||
-- Set the second from `s'.
|
||||
require
|
||||
valid_argument_for_second: 0 <= s and s <= 59
|
||||
ensure
|
||||
second_set: second = s
|
||||
end
|
||||
</code>
|
||||
|
||||
This specification of <code> set_second </code> tells us what is required of reuse consumers if they wish to use <code> set_second </code> and what <code> set_second </code> promises to do for them. Importantly, it does that without revealing how it does it does what it does.
|
||||
This specification of <code>set_second</code> tells us what is required of reuse consumers if they wish to use <code>set_second</code> and what <code>set_second</code> promises to do for them. Importantly, it does that without revealing how it does it does what it does.
|
||||
|
||||
So, this specification view, officially called the contract view, is how consumers of class <code> TIME_OF_DAY </code> would view the feature.
|
||||
So, this specification view, officially called the contract view, is how consumers of class <code>TIME_OF_DAY</code> would view the feature.
|
||||
|
||||
If this is the specification, then haven't we put the cart before the horse? The answer is yes. We have done so to illustrate the problems that assertion-based specification can help solve.
|
||||
|
||||
Instead of starting with a routine and adding a specification, we really want to start in accepted software engineering fashion with specification first, and then add implementation. Therefore, the specification you see above would exist before the implementation.
|
||||
|
||||
Now back to the concern over whether the postcondition is redundant for this simple one-line routine. Obviously, if this specification exists first, then the postcondition must be there, and it would be silly to remove it later. But, more importantly, suppose that when the producer of the class decided on an implementation, he or she chose the second design alternative we mentioned above. This would mean that the internal state of an instance of <code> TIME_OF_DAY </code> would be only one <code> INTEGER </code> with the number of seconds since midnight. That would mean that the query <code> second </code> would probably be a function that computed seconds from that one <code> INTEGER </code> instead of an attribute.
|
||||
Now back to the concern over whether the postcondition is redundant for this simple one-line routine. Obviously, if this specification exists first, then the postcondition must be there, and it would be silly to remove it later. But, more importantly, suppose that when the producer of the class decided on an implementation, he or she chose the second design alternative we mentioned above. This would mean that the internal state of an instance of <code>TIME_OF_DAY</code> would be only one <code>INTEGER</code> with the number of seconds since midnight. That would mean that the query <code>second</code> would probably be a function that computed seconds from that one <code>INTEGER</code> instead of an attribute.
|
||||
|
||||
What would change in the specification of <code> set_second </code>? Nothing. The implementation for the routine would be more complex, but what it does, setting the second in an instance of <code> TIME_OF_DAY </code>, would stay the same.
|
||||
What would change in the specification of <code>set_second</code>? Nothing. The implementation for the routine would be more complex, but what it does, setting the second in an instance of <code>TIME_OF_DAY</code>, would stay the same.
|
||||
|
||||
In summary, the precondition and postcondition ensure for use that the routine will only execute if called in a state in which the precondition is true, and then will either complete in a state in which the postcondition is true, or cause a postcondition violation exception.
|
||||
|
||||
===The Contract for a Routine===
|
||||
|
||||
Having assertions on its routines forms a contract between the <code> TIME_OF_DAY </code> class and all potential reuse consumers. The contract is much like a contract in business, with obligations and benefits for both parties.
|
||||
Having assertions on its routines forms a contract between the <code>TIME_OF_DAY</code> class and all potential reuse consumers. The contract is much like a contract in business, with obligations and benefits for both parties.
|
||||
* The client's benefits are outlined in the postcondition.
|
||||
* The client's obligations come from the precondition.
|
||||
* The supplier's obligations are in the postcondition.
|
||||
* The supplier's benefits come from the precondition.
|
||||
|
||||
We can see the specifics of these by using <code> set_second </code> as an example.
|
||||
We can see the specifics of these by using <code>set_second</code> as an example.
|
||||
* The client gets the desired value for seconds set in the instance.
|
||||
* The client must provide an argument that is valid for seconds.
|
||||
* The supplier must update the instance successfully.
|
||||
@@ -143,19 +143,18 @@ We can see the specifics of these by using <code> set_second </code> as an examp
|
||||
|
||||
===Valid State for Instances===
|
||||
|
||||
Assertions on <code> TIME_OF_DAY </code>'s routines gives us specification for each routine and guarantees that if the specification of a routine gets violated at runtime we will be served immediately with an exception. This will go a long way toward preventing invalid instances from going unnoticed in a running system and fouling up lots of other stuff.
|
||||
Assertions on <code>TIME_OF_DAY</code>'s routines gives us specification for each routine and guarantees that if the specification of a routine gets violated at runtime we will be served immediately with an exception. This will go a long way toward preventing invalid instances from going unnoticed in a running system and fouling up lots of other stuff.
|
||||
|
||||
What will help even more is something called a class invariant. Using the class invariant we are able to state what it means for an instance of a class to be valid, or as it is sometimes put, in a stable state.
|
||||
|
||||
The class invariant is an assertion like precondition and postcondition, but there is only one per class. Check [[Eiffel Classes|Eiffel Classes]] to see how the class invariant fits into the class structure.
|
||||
|
||||
How would we code the class invariant for <code> TIME_OF_DAY </code>? An instance would be valid if its hour were between 0 and 23 inclusive, minute were between 0 and 59 inclusive, and its second were between 0 and 59 inclusive. We can code the invariant as shown below.
|
||||
How would we code the class invariant for <code>TIME_OF_DAY</code>? An instance would be valid if its hour were between 0 and 23 inclusive, minute were between 0 and 59 inclusive, and its second were between 0 and 59 inclusive. We can code the invariant as shown below.
|
||||
<code>
|
||||
invariant
|
||||
|
||||
hour_valid: 0 <= hour and hour <= 23
|
||||
minute_valid: 0 <= minute and minute <= 59
|
||||
second_valid: 0 <= second and second <= 59
|
||||
invariant
|
||||
hour_valid: 0 <= hour and hour <= 23
|
||||
minute_valid: 0 <= minute and minute <= 59
|
||||
second_valid: 0 <= second and second <= 59
|
||||
</code>
|
||||
|
||||
The name invariant implies that the assertion can never be false ... and that's true up to a point. It's really more like, "it must be true at times when it really counts".
|
||||
@@ -164,7 +163,7 @@ At runtime the invariant must be true for an instance at anytime that the instan
|
||||
|
||||
As with the assertions on routines, if ever the invariant is not true when it should be, then a class invariant violation occurs.
|
||||
|
||||
Remember in the example above, that the features <code> hour </code>, <code> minute </code>, and <code> second </code> are queries, but they could be either attributes or functions.
|
||||
Remember in the example above, that the features <code>hour</code>, <code>minute</code>, and <code>second</code> are queries, but they could be either attributes or functions.
|
||||
|
||||
==The Contract for a Class==
|
||||
|
||||
@@ -198,21 +197,21 @@ For class invariants, if any new invariants are coded in an heir, they will be a
|
||||
|
||||
That is simple enough. And the situation is also simple for effective routines inherited and left unchanged ... the contracts stand as written.
|
||||
|
||||
From our example above you may have gotten the idea that contracts are really useful only for effective routines. Such is not the case. In fact, specifying a contract on a deferred routine is really a powerful notion. It says not only that effective descendants must provide an implementation for this routine, but also that there is a contract that must be satisfied. Effecting or redefining a routine in a descendant class will not make the contract go away. Here is an feature from the Base Library deferred class <code> ACTIVE </code> which models data structures with a current item, and is an ancestor to many effective container type classes.
|
||||
From our example above you may have gotten the idea that contracts are really useful only for effective routines. Such is not the case. In fact, specifying a contract on a deferred routine is really a powerful notion. It says not only that effective descendants must provide an implementation for this routine, but also that there is a contract that must be satisfied. Effecting or redefining a routine in a descendant class will not make the contract go away. Here is an feature from the Base Library deferred class <code>ACTIVE</code> which models data structures with a current item, and is an ancestor to many effective container type classes.
|
||||
<code>
|
||||
feature -- Element change
|
||||
|
||||
replace (v: G) is
|
||||
-- Replace current item by `v'.
|
||||
require
|
||||
writable: writable
|
||||
deferred
|
||||
ensure
|
||||
item_replaced: item = v
|
||||
end
|
||||
replace (v: G)
|
||||
-- Replace current item by `v'.
|
||||
require
|
||||
writable: writable
|
||||
deferred
|
||||
ensure
|
||||
item_replaced: item = v
|
||||
end
|
||||
</code>
|
||||
|
||||
Feature <code> replace </code> carries the semantics necessary for replacing an item in an <code> ACTIVE </code>. It does not, however provide an implementation. All implementers must produce versions of <code> replace </code> that satisfy the contract specified here.
|
||||
Feature <code>replace</code> carries the semantics necessary for replacing an item in an <code>ACTIVE</code>. It does not, however provide an implementation. All implementers must produce versions of <code>replace</code> that satisfy the contract specified here.
|
||||
|
||||
It actually is possible to alter a feature assertion in an effected or redefined version(technically its a replacement of the original version):
|
||||
* The precondition can only become weaker than in the inherited contract.
|
||||
@@ -230,7 +229,7 @@ In the section [[Adding Class Features|Adding Class Features]] , we promised to
|
||||
|
||||
One of these is the tendency of mature Eiffel programmers to write routines that are quite short. It should be clear by now that we wish to build a contract on each routine. The contract describes the semantics of the routine in a declarative fashion. In other words, it tells what the routine does, without giving an indication of how it does it.
|
||||
|
||||
Try to imagine giving a declarative description of a routine that was 50 lines long. Hardly possible. So decomposition of complex computations into chunks small enough to describe with assertions is what gets done.
|
||||
Try to imagine giving a declarative description of a routine that was 50 lines long. This could get ugly. So experienced Eiffel developers decompose complex computations into chunks small enough to be described through a clear, concise set of assertions.
|
||||
|
||||
===Command/Query Separation===
|
||||
|
||||
@@ -252,51 +251,51 @@ You have seen fairly typical assertions written in the examples above. Study the
|
||||
|
||||
One is that, as you can probably imagine, it is not a good thing to cause an exception during the process of checking an assertion. One of the most common ways to cause such an exception is to apply a feature to a Void reference.
|
||||
|
||||
The way to avoid this is to use the non-strict booleans " <code> and then </code>" and " <code> or else </code>". These forms of " <code> and </code>" and " <code> or </code>" do not force the checking of all conditions. As soon as a determination can be made, they stop checking. It is typical to see " <code> and then </code>" used to avoid applying a feature to a void reference in preconditons. Below is a creation procedure that uses a non-strict boolean in its precondition.
|
||||
The way to avoid this is to use the non-strict booleans "<code>and then</code>" and "<code>or else</code>". These forms of "<code>and</code>" and "<code>or</code>" do not force the checking of all conditions. As soon as a determination can be made, they stop checking. It is typical to see "<code>and then</code>" used to avoid applying a feature to a void reference in preconditons. Below is a creation procedure that uses a non-strict boolean in its precondition.
|
||||
<code>
|
||||
make (a_nm: STRING; a_offset: INTEGER) is
|
||||
-- Initalize with name `a_nm' and utcoffset `a_offset'
|
||||
require
|
||||
name_not_empty: a_nm /= Void and then not a_nm.is_empty
|
||||
offset_valid: a_offset >= -12 and a_offset <= 12
|
||||
do
|
||||
name := a_nm.twin
|
||||
utcoffset := a_offset
|
||||
ensure
|
||||
name_initialized: name.is_equal (a_nm)
|
||||
utcoffset_initialized: utcoffset = a_offset
|
||||
end
|
||||
make (a_nm: STRING; a_offset: INTEGER)
|
||||
-- Initalize with name `a_nm' and utcoffset `a_offset'.
|
||||
require
|
||||
name_not_empty: a_nm /= Void and then not a_nm.is_empty
|
||||
offset_valid: a_offset >= -12 and a_offset <= 12
|
||||
do
|
||||
name := a_nm.twin
|
||||
utcoffset := a_offset
|
||||
ensure
|
||||
name_initialized: name.is_equal (a_nm)
|
||||
utcoffset_initialized: utcoffset = a_offset
|
||||
end
|
||||
</code>
|
||||
|
||||
===Replacing Inherited Feature Assertions===
|
||||
|
||||
To replace a precondition on a feature you are effecting or redefining, you use the " <code> require </code> <code> else </code>" keywords to introduce new conditions. These conditions will be logically " <code> or </code>-ed" with the original precondition to form an new one.
|
||||
To replace a precondition on a feature you are effecting or redefining, you use the "<code>require else</code>" keywords to introduce new conditions. These conditions will be logically "<code>or</code>-ed" with the original precondition to form an new one.
|
||||
|
||||
Likewise use "<code>and </code> <code> then </code>" to add conditions to a postcondition. The added conditions will be " <code> and </code>-ed" to the original.
|
||||
Likewise use "<code>and then</code>" to add conditions to a postcondition. The added conditions will be "<code>and</code>-ed" to the original.
|
||||
|
||||
Below is an example of weakening a precondition. The first feature shown is from class <code> DYNAMIC_CHAIN </code> in the Base Library.
|
||||
Below is an example of weakening a precondition. The first feature shown is from class <code>DYNAMIC_CHAIN</code> in the Base Library.
|
||||
<code>
|
||||
remove_left is
|
||||
-- Remove item to the left of cursor position.
|
||||
-- Do not move cursor.
|
||||
require
|
||||
left_exists: index > 1
|
||||
deferred
|
||||
ensure
|
||||
new_count: count = old count - 1
|
||||
new_index: index = old index - 1
|
||||
end
|
||||
remove_left
|
||||
-- Remove item to the left of cursor position.
|
||||
-- Do not move cursor.
|
||||
require
|
||||
left_exists: index > 1
|
||||
deferred
|
||||
ensure
|
||||
new_count: count = old count - 1
|
||||
new_index: index = old index - 1
|
||||
end
|
||||
</code>
|
||||
|
||||
The next feature is from <code> DYNAMIC_LIST </code>, a proper descendant of <code> DYNAMIC_CHAIN </code>. <code> DYNAMIC_LIST </code> weakens the precondition it inherited from <code> DYNAMIC_CHAIN </code>. Originally in <code> DYNAMIC_CHAIN </code>, " <code> index </code> > 1" was required for <code> remove_left </code>. In <code> DYNAMIC_LIST </code> either " <code> index </code> > 1" or " <code> not </code> <code> before </code>" (or both) will suffice.
|
||||
The next feature is from <code>DYNAMIC_LIST</code>, a proper descendant of <code>DYNAMIC_CHAIN</code>. <code>DYNAMIC_LIST</code> weakens the precondition it inherited from <code>DYNAMIC_CHAIN</code>. Originally in <code>DYNAMIC_CHAIN</code>, "<code>index > 1</code>" was required for <code>remove_left</code>. In <code>DYNAMIC_LIST</code> either "<code>index > 1</code>" or "<code>not before</code>" (or both) will suffice.
|
||||
<code>
|
||||
remove_left is
|
||||
-- Remove item to the left of cursor position.
|
||||
-- Do not move cursor.
|
||||
require else
|
||||
not_before: not before
|
||||
deferred
|
||||
end
|
||||
remove_left
|
||||
-- Remove item to the left of cursor position.
|
||||
-- Do not move cursor.
|
||||
require else
|
||||
not_before: not before
|
||||
deferred
|
||||
end
|
||||
</code>
|
||||
|
||||
==Not Writing Assertions==
|
||||
@@ -305,13 +304,13 @@ Let's close this discussion of Design by Contract with one more interesting and
|
||||
|
||||
The contract exists, even though you do not code it explicitly. If it were written out, it would look as follows.
|
||||
<code>
|
||||
my_routine is
|
||||
-- My descriptive header comment
|
||||
require
|
||||
True
|
||||
ensure
|
||||
True
|
||||
end
|
||||
my_routine
|
||||
-- My descriptive header comment
|
||||
require
|
||||
True
|
||||
ensure
|
||||
True
|
||||
end
|
||||
</code>
|
||||
|
||||
What does this mean? It means that you have selected the weakest possible precondition and postcondition for your routine. Of course, this may be perfectly valid under some circumstances.
|
||||
|
||||
@@ -17,15 +17,15 @@ If we can have a runtime object that represents an operation, then we can place
|
||||
|
||||
This is a very desirable model for event driven processing, like graphical user interfaces. The operations that are executed when a user take some action like clicking on a button, could be represented by agents. When the user interface element is initialized, agents that represent the action routines are stored within the interface element. Then at the time that an event, say a button click, occurs, the agents for that event are retrieved and their associated operations are executed.
|
||||
|
||||
Another area in which agents are commonly used is in traversing data structures. Many of the data structure classes in the Base Library include routines which take agents as there arguments. For example, the feature <code> do_all </code> takes an agent which represents some procedure and will apply the procedure to every item in the structure.
|
||||
Another area in which agents are commonly used is in traversing data structures. Many of the data structure classes in the Base Library include routines which take agents as there arguments. For example, the feature <code>do_all</code> takes an agent which represents some procedure and will apply the procedure to every item in the structure.
|
||||
|
||||
==Classes to Model Operations==
|
||||
|
||||
We know that there are two types of routines in Eiffel, functions and procedures.
|
||||
|
||||
Not surprisingly, the implementation of agents relies on three classes in the Base Library. Class <code> ROUTINE </code>, and its heirs <code> FUNCTION </code> and <code> PROCEDURE </code>.
|
||||
Not surprisingly, the implementation of agents relies on three classes in the Base Library. Class <code>ROUTINE</code>, and its heirs <code>FUNCTION</code> and <code>PROCEDURE</code>.
|
||||
|
||||
When you use an agent from a client routine, you will be building an instance of either <code> FUNCTION </code> or <code> ROUTINE </code>. This happens implicitly as you will see.
|
||||
When you use an agent from a client routine, you will be building an instance of either <code>FUNCTION</code> or <code>ROUTINE</code>. This happens implicitly as you will see.
|
||||
|
||||
==Using Agents==
|
||||
|
||||
@@ -34,18 +34,18 @@ Below is an instruction which passes an agent as an argument to a procedure.
|
||||
button.select_actions.extend (agent gauge.step_forward)
|
||||
</code>
|
||||
|
||||
In this example, the producer wants to add the action of stepping the gauge forward in the event that a button is clicked. The keyword " <code> agent </code>" is used to indicate that at runtime an object of type <code> PROCEDURE </code> should be created which represents applying the feature <code> step_forward </code> to the object attached to <code> gauge </code>. It is the object of type <code> PROCEDURE </code> that is passed as the argument.
|
||||
In this example, the producer wants to add the action of stepping the gauge forward in the event that a button is clicked. The keyword " <code>agent</code>" is used to indicate that at runtime an object of type <code>PROCEDURE</code> should be created which represents applying the feature <code>step_forward</code> to the object attached to <code>gauge</code>. It is the object of type <code>PROCEDURE</code> that is passed as the argument.
|
||||
|
||||
It is important to understand that <code> step_forward </code> does not get applied at the point that the instruction above is executed. Rather the procedure object that represents <code> step_forward </code> is given to the button to hold in reserve. Then at the point that the button click event takes place, the button will go through its list of <code> select_actions </code> executing their associated routines. Only then does <code> step_forward </code>get applied to <code> gauge </code>.
|
||||
It is important to understand that <code>step_forward</code> does not get applied at the point that the instruction above is executed. Rather the procedure object that represents <code>step_forward</code> is given to the button to hold in reserve. Then at the point that the button click event takes place, the button will go through its list of <code>select_actions</code> executing their associated routines. Only then does <code>step_forward</code>get applied to <code>gauge</code>.
|
||||
|
||||
===Agents with Arguments===
|
||||
|
||||
In this example, the routine " <code> step_forward </code>" on which the agent is based takes no arguments. If you drilled down into the workings of this example you would find that class that implements the feature <code> extend </code> is class <code> EV_NOTIFY_ACTION_SEQUENCE </code>. You would also see that the signature for the feature <code> extend </code> is as essentially as follows.
|
||||
In this example, the routine " <code>step_forward</code>" on which the agent is based takes no arguments. If you drilled down into the workings of this example you would find that class that implements the feature <code>extend</code> is class <code>EV_NOTIFY_ACTION_SEQUENCE</code>. You would also see that the signature for the feature <code>extend</code> is as essentially as follows.
|
||||
<code>
|
||||
extend (v: PROCEDURE [ANY, TUPLE])
|
||||
</code>
|
||||
|
||||
We don't have to know too much about the workings of agents to see that " <code> extend </code>" takes an argument <code> v </code> which is of type <code> PROCEDURE </code>. It turns out that the actual generic parameter <code> TUPLE </code> represents the set of "open" arguments. In this case, extend is expecting an agent which has no open arguments.
|
||||
We don't have to know too much about the workings of agents to see that " <code>extend</code>" takes an argument <code>v</code> which is of type <code>PROCEDURE</code>. It turns out that the actual generic parameter <code>TUPLE</code> represents the set of "open" arguments. In this case, extend is expecting an agent which has no open arguments.
|
||||
|
||||
===Open and Closed Arguments===
|
||||
|
||||
@@ -56,7 +56,7 @@ Suppose a class has a feature declared as shown below.
|
||||
my_procedure: PROCEDURE [ANY, TUPLE]
|
||||
</code>
|
||||
|
||||
Then what can be assigned to <code> my_procedure </code>?. An agent, of course. Say the class has procedures as follows.
|
||||
Then what can be assigned to <code>my_procedure</code>?. An agent, of course. Say the class has procedures as follows.
|
||||
<code>
|
||||
no_argument_procedure is
|
||||
-- A procedure with no arguments
|
||||
@@ -76,14 +76,14 @@ Then the following assignment is valid.
|
||||
my_procedure := agent no_argument_procedure
|
||||
</code>
|
||||
|
||||
What this means is that the agent created and associated with the procedure <code> no_argument_procedure </code> must conform to the type <code> PROCEDURE </code> [ <code> ANY </code>, <code> TUPLE </code>]. The feature <code> my_procedure </code> (which is of type <code> PROCEDURE </code>) can be attached at runtime to an agent representing a procedure with no open arguments, which indeed is what <code> no_argument_procedure </code> is.
|
||||
What this means is that the agent created and associated with the procedure <code>no_argument_procedure</code> must conform to the type <code>PROCEDURE</code> [ <code>ANY</code>, <code>TUPLE</code>]. The feature <code>my_procedure</code> (which is of type <code>PROCEDURE</code>) can be attached at runtime to an agent representing a procedure with no open arguments, which indeed is what <code>no_argument_procedure</code> is.
|
||||
|
||||
Now let's turn our attention to the other procedure <code> two_argument_procedure </code>. You might think that because it takes two arguments, that you would not be able to build an agent from it which could be assigned to the attribute <code> my_procedure </code>. But you can do it by closing the two arguments at the time that the agent is created, as in the following.
|
||||
Now let's turn our attention to the other procedure <code>two_argument_procedure</code>. You might think that because it takes two arguments, that you would not be able to build an agent from it which could be assigned to the attribute <code>my_procedure</code>. But you can do it by closing the two arguments at the time that the agent is created, as in the following.
|
||||
<code>
|
||||
my_procedure := agent two_argument_procedure (1, 2) -- Is Valid
|
||||
</code>
|
||||
|
||||
What happens here is that values are fixed for those arguments at the time that the agent, an object of type <code> PROCEDURE </code> [ <code> ANY </code>, <code> TUPLE </code>] is created.
|
||||
What happens here is that values are fixed for those arguments at the time that the agent, an object of type <code>PROCEDURE</code> [ <code>ANY</code>, <code>TUPLE</code>] is created.
|
||||
|
||||
So this is the wonderful thing about agents. A routine which will be represented as an agent does not have to be an exact fit for the expected signature. By closing some arguments at agent creation, you have effectively produced a new and conforming routine.
|
||||
|
||||
@@ -96,21 +96,21 @@ To leave an argument open, you hold its place with a question mark. If you inten
|
||||
my_procedure := agent two_argument_procedure -- Both arguments left open
|
||||
</code>
|
||||
|
||||
If an argument is open, then it means that a value is not provided for that argument at the time that the agent is created. The implication is that the value must be provided at some time prior to the time that the agent's associated routine gets executed. A precondition to executing a routine associated with an agent is that the agent has a valid set of arguments (called operands within the <code> ROUTINE </code> classes) for the call. If you were to leave one or both of the arguments to <code> two_argument_procedure </code> open as in the examples above, the assignment would still work due to the rules governing <code> TUPLE </code> conformance. But, at runtime unless the other arguments had been provided, the " <code> valid operands </code>" precondition would be violated.
|
||||
If an argument is open, then it means that a value is not provided for that argument at the time that the agent is created. The implication is that the value must be provided at some time prior to the time that the agent's associated routine gets executed. A precondition to executing a routine associated with an agent is that the agent has a valid set of arguments (called operands within the <code>ROUTINE</code> classes) for the call. If you were to leave one or both of the arguments to <code>two_argument_procedure</code> open as in the examples above, the assignment would still work due to the rules governing <code>TUPLE</code> conformance. But, at runtime unless the other arguments had been provided, the " <code>valid operands</code>" precondition would be violated.
|
||||
|
||||
Let's see an example in which we leave a target open. Suppose we have a class that has a feature coded as below
|
||||
<code>
|
||||
my_strings: LINKED_LIST [STRING]
|
||||
</code>
|
||||
|
||||
and some code to put some strings in <code> my_strings </code>:
|
||||
and some code to put some strings in <code>my_strings</code>:
|
||||
<code>
|
||||
create my_things.make
|
||||
my_strings.extend ("Hello")
|
||||
my_strings.extend ("World!")
|
||||
</code>
|
||||
|
||||
Our class also has a feature called <code> print_on_new_line </code> which we created to print a string preceded by a new line character.
|
||||
Our class also has a feature called <code>print_on_new_line</code> which we created to print a string preceded by a new line character.
|
||||
<code>
|
||||
print_on_new_line (s: STRING) is
|
||||
-- Print `s' preceded by a new line
|
||||
@@ -119,7 +119,7 @@ Our class also has a feature called <code> print_on_new_line </code> which we cr
|
||||
end
|
||||
</code>
|
||||
|
||||
Now suppose we want to print the values of all the strings in <code> my_strings </code> each on a separate line by invoking <code> print_on_new_line </code>. Traditionally, we would do it by traversing the <code> LINKED_LIST </code> and printing each item. Like this:
|
||||
Now suppose we want to print the values of all the strings in <code>my_strings</code> each on a separate line by invoking <code>print_on_new_line</code>. Traditionally, we would do it by traversing the <code>LINKED_LIST</code> and printing each item. Like this:
|
||||
<code>
|
||||
from
|
||||
my_list.start
|
||||
@@ -131,30 +131,30 @@ Now suppose we want to print the values of all the strings in <code> my_strings
|
||||
end
|
||||
</code>
|
||||
|
||||
The availability of agents gives us new options. <code> LINKED_LIST </code> has a feature <code> do_all </code> which comes to it from its ancestor <code> LINEAR </code>. The <code> do_all </code> feature's signature looks like this:
|
||||
The availability of agents gives us new options. <code>LINKED_LIST</code> has a feature <code>do_all</code> which comes to it from its ancestor <code>LINEAR</code>. The <code>do_all</code> feature's signature looks like this:
|
||||
<code>
|
||||
do_all (action: PROCEDURE [ANY, TUPLE [G]])
|
||||
</code>
|
||||
|
||||
As an argument <code> do_all </code> takes an agent based on a procedure with one open argument which is the same type as the list items (in this class, <code> G </code> is the formal generic parameter representing the type of the items being stored). Then it traverses the list executing the routine associated with that agent and roviding the current list item to satisfy the open argument.
|
||||
As an argument <code>do_all</code> takes an agent based on a procedure with one open argument which is the same type as the list items (in this class, <code>G</code> is the formal generic parameter representing the type of the items being stored). Then it traverses the list executing the routine associated with that agent and roviding the current list item to satisfy the open argument.
|
||||
|
||||
Instead of coding the loop shown above, we can code this instruction:
|
||||
<code>
|
||||
my_list.do_all (agent print_on_new_line (?))
|
||||
</code>
|
||||
|
||||
we leave the argument to <code> print </code> open, and <code> do_all </code> will provide it as a reference to the current list item as it traverses the list.
|
||||
we leave the argument to <code>print</code> open, and <code>do_all</code> will provide it as a reference to the current list item as it traverses the list.
|
||||
|
||||
===Targets for Agents' Routines===
|
||||
|
||||
In Eiffel every routine must be applied against a target object. In our model for computation, <code> x </code>. <code> f </code> ( <code> a </code>, ...), <code> x </code> is the target of the application of feature <code> f </code>. In the case of an agent, the agent must account for objects for each of the arguments and an object for the target of the routine.
|
||||
In Eiffel every routine must be applied against a target object. In our model for computation, <code>x</code>. <code>f</code> ( <code>a</code>, ...), <code>x</code> is the target of the application of feature <code>f</code>. In the case of an agent, the agent must account for objects for each of the arguments and an object for the target of the routine.
|
||||
|
||||
Let's identify the targets in the examples shown. First:
|
||||
<code>
|
||||
button.select_actions.extend (agent gauge.step_forward)
|
||||
</code>
|
||||
|
||||
Here the target is the object attached to the entity "gauge" which is (although you cannot determine it from this line taken out of context) an object of type <code> EV_GAUGE </code>.
|
||||
Here the target is the object attached to the entity "gauge" which is (although you cannot determine it from this line taken out of context) an object of type <code>EV_GAUGE</code>.
|
||||
|
||||
How about this:
|
||||
<code>
|
||||
@@ -177,20 +177,20 @@ Suppose in our list of strings example, we wanted to print the strings, then con
|
||||
my_list.do_all (agent print_on_new_line (?))
|
||||
</code>
|
||||
|
||||
In between printing the list two times, we provide <code> do_all </code> with an agent that representing the <code> STRING </code> class's feature <code> to_lower </code> which will convert each string in the list to lower case. Notice that <code> to_lower </code> does not take an argument of type <code> STRING </code> as <code> print_on_new_line </code> did. Rather it gets applied to an instance of <code> STRING </code>, so it is targeted to a string. So we leave its target open and <code> do_all </code> provides the current list item as the target.
|
||||
In between printing the list two times, we provide <code>do_all</code> with an agent that representing the <code>STRING</code> class's feature <code>to_lower</code> which will convert each string in the list to lower case. Notice that <code>to_lower</code> does not take an argument of type <code>STRING</code> as <code>print_on_new_line</code> did. Rather it gets applied to an instance of <code>STRING</code>, so it is targeted to a string. So we leave its target open and <code>do_all</code> provides the current list item as the target.
|
||||
|
||||
Agents for Functions
|
||||
|
||||
So far all the agents that we have coded have created instances of <code> PROCEDURE </code>. But functions are routines and can be represented as agents as well. The difference is that functions have a return value.
|
||||
So far all the agents that we have coded have created instances of <code>PROCEDURE</code>. But functions are routines and can be represented as agents as well. The difference is that functions have a return value.
|
||||
|
||||
Let's extend the string example by using an agent that represents a function. Suppose we wanted to print only those strings which contain a particular character, say the exclamation point.
|
||||
|
||||
Here again we'll use a feature of the <code> LINKED_LIST </code> class. There is a feature called <code> do_if </code> which takes two agents as arguments. One is an action procedure like the argument that <code> do_all </code> takes, and the other is a function which returns a boolean and used as a test. As each list item is current, the test is applied first. If the result is true, then the action is applied with the current item.
|
||||
Here again we'll use a feature of the <code>LINKED_LIST</code> class. There is a feature called <code>do_if</code> which takes two agents as arguments. One is an action procedure like the argument that <code>do_all</code> takes, and the other is a function which returns a boolean and used as a test. As each list item is current, the test is applied first. If the result is true, then the action is applied with the current item.
|
||||
<code>
|
||||
my_list.do_if (agent print_on_new_line(?), agent {STRING}.has('!'))
|
||||
</code>
|
||||
|
||||
The agent for the action is the same as we used earlier. We've added an agent for the test. It represents applying the <code> has </code> feature of the <code> STRING </code> class. Here the target is left open, because we want each of the strings in the list to be the target of <code> has </code>.
|
||||
The agent for the action is the same as we used earlier. We've added an agent for the test. It represents applying the <code>has</code> feature of the <code>STRING</code> class. Here the target is left open, because we want each of the strings in the list to be the target of <code>has</code>.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -32,34 +32,34 @@ There is an Eiffel mechanism called the rescue clause which facilitates the firs
|
||||
|
||||
===The Rescue Clause===
|
||||
|
||||
The <code> rescue </code> clause is part of the routine structure we saw in [[Adding Class Features|Adding Class Features]] . The rescue clause is a sequence of instructions introduced by the keyword " <code> rescue </code>". At the point that an exception occurs, the processing of the normal instructions in the routine body will cease, and the instructions in the rescue clause will be executed instead.
|
||||
The <code>rescue</code> clause is part of the routine structure we saw in [[Adding Class Features|Adding Class Features]] . The rescue clause is a sequence of instructions introduced by the keyword "<code>rescue</code>". At the point that an exception occurs, the processing of the normal instructions in the routine body will cease, and the instructions in the rescue clause will be executed instead.
|
||||
|
||||
If the instructions in the rescue clause can set things up so that it mightprove fruitful to attempt to retry the routine, it can do so by issuing a <code> retry </code> instruction. When the <code> retry </code> instruction is executed, the routine is restarted from its beginning, although local entities are not re-initialized. You will see why inthe example below.
|
||||
If the instructions in the rescue clause can set things up so that it might prove fruitful to attempt to retry the routine, it can do so by issuing a <code>retry</code> instruction. When the <code>retry</code> instruction is executed, the routine is restarted from its beginning, although local entities are not re-initialized. You will see why in the example below.
|
||||
|
||||
If the rescue clause exits without issuing a <code> retry </code> instruction, then the routine fails.
|
||||
If the rescue clause exits without issuing a <code>retry</code> instruction, then the routine fails.
|
||||
|
||||
It should be noted that rescue clauses and retry instructions are not something that are used commonly. Out of the approximately 2000 class in the delivered Eiffel libraries, there are only 16 occurrences. Many of these are oriented toward network and database operations for which some reasonable recovery might be possible.
|
||||
<code>
|
||||
transmit: (p: PACKET)
|
||||
-- Transmit packet `p'
|
||||
require
|
||||
packet_not_void: p /= Void
|
||||
local
|
||||
current_retries: INTEGER
|
||||
r: RANDOM_NUMBER_GENERATOR
|
||||
do
|
||||
line.send (p)
|
||||
rescue
|
||||
if current_retries < max_retries then
|
||||
r.next
|
||||
wait_millisecs (r.value_between (20, 500))
|
||||
current_retries := current_retries + 1
|
||||
retry
|
||||
end
|
||||
end
|
||||
transmit: (p: PACKET)
|
||||
-- Transmit packet `p'
|
||||
require
|
||||
packet_not_void: p /= Void
|
||||
local
|
||||
current_retries: INTEGER
|
||||
r: RANDOM_NUMBER_GENERATOR
|
||||
do
|
||||
line.send (p)
|
||||
rescue
|
||||
if current_retries < max_retries then
|
||||
r.next
|
||||
wait_millisecs (r.value_between (20, 500))
|
||||
current_retries := current_retries + 1
|
||||
retry
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
In the example above, <code> rescue </code> is used to recover from a situation in which an exception occurs in trying to send a packet. When the exception occurs the rescue clause will, if the maximum number of retries has not been reached, wait for some random length of time. Then, after having updated the number of retries, it will issue the <code> retry </code> instruction. If the maximum number of retries is reached, the rescue clause will exit without executing the retry, constituting a failure.
|
||||
In the example above, <code>rescue</code> is used to recover from a situation in which an exception occurs in trying to send a packet. When the exception occurs the rescue clause will, if the maximum number of retries has not been reached, wait for some random length of time. Then, after having updated the number of retries, it will issue the <code>retry</code> instruction. If the maximum number of retries is reached, the rescue clause will exit without executing the retry, constituting a failure.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,9 +22,7 @@ feature -- Access
|
||||
|
||||
item: ANY
|
||||
-- The thing currently pointed to by cursor
|
||||
|
||||
...
|
||||
|
||||
feature -- Element change
|
||||
|
||||
put (new_item: ANY)
|
||||
|
||||
Reference in New Issue
Block a user