Re: Criteria to decide what is private?
- From: Miguel Oliveira e Silva <mos@xxxxxxxxx>
- Date: Fri, 19 Jan 2007 15:43:15 +0000
"Daniel T." wrote:
Miguel Oliveira e Silva <mos@xxxxxxxxx> wrote:
"Daniel T." wrote:
To recap:
interface Range
{
// invariant: low() <= high()
int low();
int high();
}
I said that putting sets in the class would expose the invariant
and you asked, "which invariant?"
The invariant "low() <= high()." If we put sets in the class with
conventional definitions, then clients will have to make sure the
invariant stays true. That's supposed to be the Range class' job.
It is Range's responsibility to ensure its invariant, regardless of
its services being only queries ("getters") or queries and commands
("setters").
Agreed.
If by any chance an incorrectly used command might compromise the
invariant, then it is the class (Range) responsibility to attach a
proper precondition to that service (in which case, the client is
responsible to ensure, not the invariant, but the command's
precondition).
Now, keep in mind that if a precondition is not satisfied, that
represents a bug in the client, not the server (i.e., it is the client's
responsibility to satisfy the precondition.) So let's say that we put
the precondition "v <= high()" and a post condition "low() == v" where
'v' is the parameter of the method. low() == v and v <= high() therefore
low() <= high(). You are thus making the precondition the same as the
invariant.
It is not. The invariant applies to the object (internal) state.
The parameter "v" is not part of the object's state (there is
a substantial difference between the condition "before-action"
and the condition "after-action" when asserting the correctness
of a program).
The client should never be obligated to know the supplier's
implementation code (which is the one which might break
invariants). You are assuming that the client is assured that the
value of v will became low()'s value (that might not be true because
a precondition should fail before such disastrous event could ever
takes place).
The failure was due to a false precondition, not a false invariant.
Which such a precondition, the invariant becomes the clients'
responsibility.
No (never).
The invariant is the supplier responsibility. He may, however, choose to
impose preconditions to clients in some of its services in order to make
sure that it can meet its part of the contract (which is quite different
than saying that the invariant is the responsibility of clients).
It is the implementation code of setLow(v):
attr_low = v; // assuming a protected attribute 'attr_low' to represent low
that ensures the invariant. This code belongs to the supplier (not the client).
Yet, we both agreed that it is the Range class' responsibility to ensure
the invariant...
I certainly agree with that.
(I'm not so sure about you.)
In fact it is the presence of commands that makes the existence
of explicit (and testable as in Eiffel) invariants so important
for maximizing class reliability (correctness and robustness).
The invariant is exposed is when - as you correctly put
it - it is the clients responsibility to ensure it:
meaning when there exists a public writable attribute.
Lets take a look to a simple example (Eiffel syntax):
class PERSON
public
age: INTEGER; -- in Eiffel public attributes can only be used a "rvalues"
set_age(a: INTEGER) is
require -- precondition
non_negative_age: a >= 0
do
age := a
ensure -- postcondition
age = a
end;
invariant
age >= 0
end -- PERSON
You have demonstrated the exact same problem using only one variable.
The precondition is "a >= 0" and the postcondition is "age = a". a >= 0
and age = a therefore age >= 0. The invariant is expaosed to the client
and for exactly the same reason.
It is not. It is a precondition failure (not an invariant failure).
This property is extremely important to build reliable programs
because when a precondition fails the supplier object remains
in a stable state (its invariant holds), hence it can be used in the
future by other clients (which, for example in a concurrent
multi-threaded program, might even be part of programs
of different threads).
I advise you to read a good source on DbC (Chapters 6, 11
and 12 from Meyer's Object-Oriented Software Construction
2ed, would be an excellent choice).
If you add a precondition to the method that L <= high(), then you
are literally requiring the client to ensure that low() <= high().
The class is the one that is supposed to do that.
The client is not required to ensure the invariant (he is not
required to know what is happening inside setLow method
implementation). He is correctly required to ensure the method
precondition (which is L <= high() and not low() <= high() ).
The post-condition tells the client what is happening inside the setLow
method (the client doesn't know exactly how it is implemented, but he
knows abstractly what it does.)
The postcondition tells the client what is the desired result
of whatever happens inside the method's implementation
(and of any of its possible redefinitions in descendant classes).
It is (always) the class responsibility to ensure its invariant.
The client is required to observe preconditions, in which
case it is ensured (if the class is correct) that both the
method's postcondition and the class invariant will hold.
CLIENT: precondition
SUPPLIER: invariant and postcondition
Since (due to program errors) a client might try to use
objects in unstable states (which is meaningless, and
even if the precondition is true the class might be
unable to ensure postconditions) the full correctness
condition is:
{INV and PRE} routine-body {INV and POST}
The invariant which is required to be observed at
precondition time has nothing to do with current's
client use of the object. It is the consequence of
past object uses. On the other hand, the invariant
after the execution body is required to be met by
routine-body (see the difference?).
-miguel
--
Miguel Oliveira e Silva
DETI-IEETA, Universidade de Aveiro, PORTUGAL
.
- Follow-Ups:
- Re: Criteria to decide what is private?
- From: Daniel T.
- Re: Criteria to decide what is private?
- References:
- Encapsulation vs Extensibility
- From: Anthony Paul
- Re: Encapsulation vs Extensibility
- From: S Perryman
- Re: Encapsulation vs Extensibility
- From: Mark Nicholls
- Criteria to decide what is private? (was: Encapsulation vs Extensibility)
- From: Daniel T.
- Re: Criteria to decide what is private? (was: Encapsulation vs Extensibility)
- From: Mark Nicholls
- Re: Criteria to decide what is private? (was: Encapsulation vs Extensibility)
- From: Daniel T.
- Re: Criteria to decide what is private? (was: Encapsulation vs Extensibility)
- From: Mark Nicholls
- Re: Criteria to decide what is private? (was: Encapsulation vs Extensibility)
- From: Daniel T.
- Re: Criteria to decide what is private? (was: Encapsulation vs Extensibility)
- From: Mark Nicholls
- Re: Criteria to decide what is private? (was: Encapsulation vs Extensibility)
- From: Daniel T.
- Re: Criteria to decide what is private? (was: Encapsulation vs Extensibility)
- From: Mark Nicholls
- Re: Criteria to decide what is private? (was: Encapsulation vs Extensibility)
- From: Daniel T.
- Re: Criteria to decide what is private?
- From: S Perryman
- Re: Criteria to decide what is private?
- From: Daniel T.
- Re: Criteria to decide what is private?
- From: S Perryman
- Re: Criteria to decide what is private?
- From: Daniel T.
- Re: Criteria to decide what is private?
- From: Miguel Oliveira e Silva
- Re: Criteria to decide what is private?
- From: Daniel T.
- Encapsulation vs Extensibility
- Prev by Date: Re: Encapsulation vs Extensibility
- Next by Date: Re: DbC and unspecified state
- Previous by thread: Re: Criteria to decide what is private?
- Next by thread: Re: Criteria to decide what is private?
- Index(es):
Relevant Pages
|