Encapsulation vs Extensibility

This is a discussion on Encapsulation vs Extensibility within the Object forums in Theory and Concepts category; 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?" Not quite. You wrote (emphasis is mine) : "For that interface, putting in the sets would expose the invariant to *outsiders* ." The invariant is *already exposed* to "outsiders" , merely by being *defined* in the type spec. What has the addition of set ops done to change this ?? (I define outsiders here as ...

Go Back   Application Development Forum > Theory and Concepts > Object

Object Mix

Register FAQ Calendar Search Today's Posts Mark Forums Read
  #51  
Old 01-19-2007, 05:49 AM
S Perryman
Guest
 
Default Re: Criteria to decide what is private? [LONG]

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?"


Not quite. You wrote (emphasis is mine) :

"For that interface, putting in the sets would expose the invariant to
*outsiders* ."


The invariant is *already exposed* to "outsiders" , merely by being
*defined* in the type spec. What has the addition of set ops done to
change this ??

(I define outsiders here as the users/inheritors of the Range type - if
this is not what you intend the term to mean, feel free to provide your
definition and we can re-discuss)


> If we put sets in the class with conventional definitions


What is the "conventional definition" ??


> then clients will have to make sure the
> invariant stays true. That's supposed to be the Range class' job.


Without the "conventional definition" being stated, who can say ??
But while I wait for that definition ...

***

There is a relationship between invariants and pre/post conditions.
FORALL type T, property P IN T :

pre(P) = pre-conditions(P) AND invariant(T)
post(P) = post-conditions(P) AND invariant(T)

The Range *implementor* is required to ensure its invariants always hold.
For any property that is accessed by a user, the Range implementor is also
required to ensure that the post-conditions for that property hold.

The *user* is required to ensure for any property accessed, that
*pre-conditions(P)* for that property hold, *before* the property is
accessed.


> If you add "setLow( int L )" to the interface above, what will be its
> postcondition?


We have :

pre-conditions(setLow) = {}
post-conditions(setLow) = {}
invariant(Range) = low() <= high()

So:

pre(setLow) = post(setLow) = (low() <= high() )

I have a Range instance R, that currently represents the range [2,3] .
I do the following :

R.setLow(4) ;

What happens with the correctness artifacts ??

- pre(setLow) = true.

obviously

- post(setLow) = true.

obviously


What are the subsequent values of high/low after invoking setLow ??

UNDEFINED !!!

The Range type has *no statement* of what those values will be.
All we know is whatever the values are, low <= high.


> If you make it: low() == L


Now we have :

pre(setLow) = low() <= high()
post(setLow) = (low() == L) AND (low() <= high() )

I have a Range instance R, that currently represents the range [2,3] .
I do the following :

R.setLow(4) ;

What happens with the correctness artifacts ??

- pre(setLow) = true.

obviously

- post(setLow) = true.

obviously


What are the subsequent values of high/low after invoking setLow ??

low = 4
high = UNDEFINED !!!

The Range type has *no statement* of what the high value will be.
All we know is whatever the values are, low <= high.


> then what do you do if someone calls
> myRange.setLow( myRange.high() + 2 ) ?


See above.


> If you add a precondition to the method that L <= high()


Now we have :

pre(setLow) = (L <= high) AND (low() <= high() )
post(setLow) = (low() == L) AND (low() <= high() )

I have a Range instance R, that currently represents the range [2,3] .
I do the following :

R.setLow(4) ;

What happens with the correctness artifacts ??

- pre(setLow) = false

obviously


> then you are
> literally requiring the client to ensure that low() <= high().


The user is required to provide a value for L less than or equal to
the value of R.high *at that time* .


> The class is the one that is supposed to do that.


Supposed to do what (goto *** ) ??


> Of course you could weaken the postcondition of setLow(int) to something
> like: low() == min( L, high() ) but then it won't pass the conventional
> definition of a setter.


Awaiting the "conventional definition" of a setter ...


Regards,
Steven Perryman
Reply With Quote
  #52  
Old 01-19-2007, 09:00 AM
Daniel T.
Guest
 
Default Re: Criteria to decide what is private?

Miguel Oliveira e Silva <mos{}det.ua.pt> 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. Which such a precondition, the invariant becomes the clients'
responsibility.

Yet, we both agreed that it is the Range class' responsibility to ensure
the invariant...

> 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.

> > 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.)
Reply With Quote
  #53  
Old 01-19-2007, 09:15 AM
Robert Martin
Guest
 
Default Re: Encapsulation vs Extensibility

On 2007-01-12 16:06:08 -0600, "Anthony Paul" <anthonypaulo{}> said:

> While I can see that the 'private' modifier has
> its uses, I'm puzzled as to why it's advocated so much given that one
> of the strong points of OO is extensibility.


The Open-Closed Principle of OOD (See
http://www.objectmentor.com/resources/articles/ocp.pdf) says that
objects should be open for extension but closed for modification. In
other words, you should be able to change what a module does without
changing the module. Extensibility, in OO, is best achieved when you
keep the code you are extending safe from modification.

How do you protect code from the forces that would try to modify it?
You keep the variables it depends upon private. If a variable is not
private, then it is open to used in a way that the "owner" of that
variable did not intend. Indeed, using a variable in an unintended way
is the *only* reason to make the variable public or protected. But
when you use a variable in an unintended way you likely force
modifications into the owner. If, on the other hand, all the variables
of a module are private, then no modification can be caused through
unintended useage.

Privacy does not preclude extensibility. You can create public or
protected accessor methods that: 1) provide extenders access to certain
variables, and 2) ensure that the extenders don't use the variable in
an unintended way.

For example, given a variable v used by a module m, such that v should
never be negative. If you make v public or protected someone could set
it to a negative number breaking the code in m and possibly forcing
mofidication to m. However, if v is private but is accessible through
getV and setV methods; and if the setV method throws an exception if
you pass it a negative number, then m is safe, and extenders are forced
to follow the rules that m expects.

To be fair, while I am a big proponent of keeping variables private, I
have also come to rely much more on my unit tests to enforce the
appropriate use of variables. When the code enjoys 90+% unit test
coverage those tests will uncover and prevent variable misuse. This
softens the need for the compiler to enforce privacy. This is not to
say that you shoudl not make your variables private, you should. It is
to say that if you use TDD, the cost/benefit ratio changes, and you may
find that you can soften access to some variables.
--
Robert C. Martin (Uncle Bob)**| email: unclebob{}objectmentor.com
Object Mentor Inc.* * * * * **| blog:**www.butunclebob.com
The Agile Transition Experts**| web:***www.objectmentor.com
800-338-6716* * * * * * * * **|



Reply With Quote
  #54  
Old 01-19-2007, 09:30 AM
Daniel T.
Guest
 
Default Re: Criteria to decide what is private? [LONG]

In article <eoq7nm$o8t$1{}aioe.org>, S Perryman <q{}q.net> 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?"

>
> Not quite. You wrote (emphasis is mine) :
>
> "For that interface, putting in the sets would expose the invariant to
> *outsiders* ."
>
>
> The invariant is *already exposed* to "outsiders" , merely by being
> *defined* in the type spec. What has the addition of set ops done to
> change this ??
>
> (I define outsiders here as the users/inheritors of the Range type - if
> this is not what you intend the term to mean, feel free to provide your
> definition and we can re-discuss)


Our definitions of "outsiders" is the same, but I meant something
different by the word "exposed". I meant that the invariant can be
broken by outsiders.

> > If we put sets in the class with conventional definitions

>
> What is the "conventional definition" ??


void setLow( int v ) {
low = v;
}

> > If you add "setLow( int L )" to the interface above, what will be its
> > postcondition?

>
> We have :
>
> pre-conditions(setLow) = {}
> post-conditions(setLow) = {}
> invariant(Range) = low() <= high()


This is a viable option. It says that setLow does not do anything at
all. As such an implementation that does nothing for any value of L is
completely correct.

> So:
>
> pre(setLow) = post(setLow) = (low() <= high() )
>
> I have a Range instance R, that currently represents the range [2,3] .
> I do the following :
>
> R.setLow(4) ;
>
> What happens with the correctness artifacts ??
>
> - pre(setLow) = true.
>
> obviously
>
> - post(setLow) = true.
>
> obviously
>
>
> What are the subsequent values of high/low after invoking setLow ??
>
> UNDEFINED !!!


That is not how I understand contracts. As I understand it, there is an
implied contract that any state not mentioned in the postcondition will
remain invariant.

> The Range type has *no statement* of what those values will be.
> All we know is whatever the values are, low <= high.
>
>
> > If you make it: low() == L

>
> Now we have :
>
> pre(setLow) = low() <= high()
> post(setLow) = (low() == L) AND (low() <= high() )
>
> I have a Range instance R, that currently represents the range [2,3] .
> I do the following :
>
> R.setLow(4) ;
>
> What happens with the correctness artifacts ??
>
> - pre(setLow) = true.
>
> obviously
>
> - post(setLow) = true.
>
> obviously
>
>
> What are the subsequent values of high/low after invoking setLow ??
>
> low = 4
> high = UNDEFINED !!!
>
> The Range type has *no statement* of what the high value will be.
> All we know is whatever the values are, low <= high.


Again, this may be a misunderstanding on my part. If it is, then you are
correct, of course.
Reply With Quote
  #55  
Old 01-19-2007, 10:33 AM
S Perryman
Guest
 
Default Re: Criteria to decide what is private? [LONG]

Daniel T. wrote:

> In article <eoq7nm$o8t$1{}aioe.org>, S Perryman <q{}q.net> wrote:


>>The invariant is *already exposed* to "outsiders" , merely by being
>>*defined* in the type spec. What has the addition of set ops done to
>>change this ??


>>(I define outsiders here as the users/inheritors of the Range type - if
>>this is not what you intend the term to mean, feel free to provide your
>>definition and we can re-discuss)


> Our definitions of "outsiders" is the same, but I meant something
> different by the word "exposed". I meant that the invariant can be
> broken by outsiders.


OK. So this by definition means that an outsider can only break a type
invariant when accessing a type property P, by not conforming to the
pre-conditions defined for P (preconditions(P) ) .


>>>If we put sets in the class with conventional definitions


>>What is the "conventional definition" ??


> void setLow( int v ) {
> low = v;
> }


This is a typical implementation.
I wanted a typical specification (pre/post-conditions) .


DT>If you add "setLow( int L )" to the interface above, what will be its
DT>postcondition?

>>We have :


>>pre-conditions(setLow) = {}
>>post-conditions(setLow) = {}
>>invariant(Range) = low() <= high()


> This is a viable option. It says that setLow does not do anything at
> all. As such an implementation that does nothing for any value of L is
> completely correct.


Oh no. It says no such thing.
The post-condition (correctly) states that whatever value low/high are
set to as a result of being given L, low <= high.


>>So:


>>pre(setLow) = post(setLow) = (low() <= high() )


>>I have a Range instance R, that currently represents the range [2,3] .
>>I do the following :


>>R.setLow(4) ;


>>What happens with the correctness artifacts ??


>>- pre(setLow) = true.


>>obviously


>>- post(setLow) = true.


>>obviously


>>What are the subsequent values of high/low after invoking setLow ??


>>UNDEFINED !!!


> That is not how I understand contracts. As I understand it, there is an
> implied contract that any state not mentioned in the postcondition will
> remain invariant.


1. Sadly not. In the words of Liskov and Wing :

Type Specifications Need Explicit Invariants
Type Specifications Need Explicit Constraints


Assume nothing. Specify as much as possible.


2. Here is an exercise that examines the notion of other "state not
mentioned in the postcondition" remaining invariant. It is the old
favourite of type substitutability ... Circle/Ellipse.

type Ellipse
do
invariant : focusA() > 0 , focusB() > 0

pre: A > 0
post: focusA() = A
setFocusA(A) ;

pre: B > 0
post: focusB() = B
setFocusB(B) ;
end


type Circle
conforms to Ellipse
do
invariant: radius() = focusA() = focusB()

setFocusA(A) ;
setFocusB(B) ;
end


Circle c = new Circle(radius : 1) ;

c.setFocusA(2) ; // #1
c.setFocusB(3) ; // #2


Q1. What are the contracts for Ellipse::focusA(A) etc as actually
written ?? What are they for Circle::focusA(A) ??

Based on these contracts, what will the values of c.focusA() and
c.focusB() at points #1/#2 ??

Do those values conform to the contracts of Ellipse/Circle::focusA(A) ??


Q2. Repeat Q1, but replace "contracts" with "implied contracts" and
"as actually" with "when explicitly" .

Q3. Is there a difference between Q1 and Q2 ?? If so, what is the
difference ?? If there is a difference, how easy is it for a user of
a type to discern such implied contracts ??


>>The Range type has *no statement* of what those values will be.
>>All we know is whatever the values are, low <= high.


>>>If you make it: low() == L


>>Now we have :


>>pre(setLow) = low() <= high()
>>post(setLow) = (low() == L) AND (low() <= high() )


>>I have a Range instance R, that currently represents the range [2,3] .
>>I do the following :


>>R.setLow(4) ;


>>What happens with the correctness artifacts ??


>>- pre(setLow) = true.


>>obviously


>>- post(setLow) = true.


>>obviously


>>What are the subsequent values of high/low after invoking setLow ??


>>low = 4
>>high = UNDEFINED !!!


>>The Range type has *no statement* of what the high value will be.
>>All we know is whatever the values are, low <= high.


> Again, this may be a misunderstanding on my part. If it is, then you are
> correct, of course.


It may or may not be a misunderstanding (that remains to be shown) .

If it isn't, we need to state your understanding precisely so that we can
discuss things further.

If it is, we still need to state your understanding precisely, so that we
can see which parts of your understanding are correct, and which are not.

Either way, we are going to get there.


Regards,
Steven Perryman
Reply With Quote
  #56  
Old 01-19-2007, 10:43 AM
Robert Martin
Guest
 
Default Re: Encapsulation vs Extensibility

On 2007-01-12 16:06:08 -0600, "Anthony Paul" <anthonypaulo{}> said:

> Excuse my cynicism people... I've been holding this in for the past 20
> years. I will be a truly happy camper the day I see some science in
> computer science.


There is a huge difference between science and engineering and art.
Any human endeavor worth doing must have elements of all three.
Software development is no exception.

The science part of software is meager, but rigorous. The "Halting
Problem", the study of sorts and searches, the reduction of computing
to turing machines, are all evidence that we have a functioning science.

The engineering part of software is not so meager as the science; but
is less rigorous. There are many books and papers written about
engineering principles and design patterns, etc. These are neither
more, nor less, definitive than in any other engineering practice. All
engineers have certain dogmas and religions that they follow that have
no scientific basis; but that are nonetheless empirically derived and
communicated by social tradition.

It is the art that is the most elusive, and perhaps the most *human*
aspect of software. And it may be the most important. Software is a
craft, a combination of science, engineering, and art. As such, it is
an effort to create beauty. Beauty of function, beauty of form, beauty
of utility, beauty of affordability. A good software developer *cares*
about the software he writes that way an author cares about his words,
or a painter cares about his brush strokes. A professional software
developer continuously learns the science, the engineering, and the art
forms of his/her discipline.

Do not bemoan the state of software science and engineering. Do not
complain that there is too much art. If there were not art, then
software could be done by computers.
--
Robert C. Martin (Uncle Bob)**| email: unclebob{}objectmentor.com
Object Mentor Inc.* * * * * **| blog:**www.butunclebob.com
The Agile Transition Experts**| web:***www.objectmentor.com
800-338-6716* * * * * * * * **|



Reply With Quote
  #57  
Old 01-19-2007, 10:43 AM
Miguel Oliveira e Silva
Guest
 
Default Re: Criteria to decide what is private?

"Daniel T." wrote:

> Miguel Oliveira e Silva <mos{}det.ua.pt> 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


Reply With Quote
  #58  
Old 01-19-2007, 11:24 AM
Daniel T.
Guest
 
Default Re: Criteria to decide what is private?

Miguel Oliveira e Silva <mos{}det.ua.pt> wrote:

> > > 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


I'm somewhat confused about this point. Is your PERSON class an example
of an invariant being exposed or not? The comment above the code implies
to me that it is.
Reply With Quote
  #59  
Old 01-19-2007, 11:45 AM
Miguel Oliveira e Silva
Guest
 
Default Re: Criteria to decide what is private?

"Daniel T." wrote:

> Miguel Oliveira e Silva <mos{}det.ua.pt> wrote:
>
> > > > 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

>
> I'm somewhat confused about this point. Is your PERSON class an example
> of an invariant being exposed or not?


No. The invariant is correctly protected by the class itself.

> The comment above the code implies to me that it is.


(Sorry.)

The invariant is exposed to clients (which I'm reading as
possibly being compromised by clients) if the class has
public writable attributes (which are not possible in Eiffel,
but quite common in C++ and Java).

Even when the supplier has a missing precondition
in the specification (and implementation) of its class,
the invariant is not exposed, because is still the supplier
fault for not having a correct specification of its class.

-miguel

--
Miguel Oliveira e Silva
DETI-IEETA, Universidade de Aveiro, PORTUGAL


Reply With Quote
Reply


Thread Tools
Display Modes


All times are GMT -5. The time now is 07:57 AM.


Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
vB Ad Management by =RedTyger=

In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.