Re: Simple inheritence question



Responding to Stevenwurster...

In this simple context you can ensure there is never any inconsistency
by eliminating 'bool b' from the constructor in the second example and
letting the constructor set the value of is_blank based upon the value
of letter.  In addition, it is highly unlikely that someone is going to
come along a year from now and add a set_is_blank(bool b) setter to the
Scrabble_Tile class and then use it to create an inconsistency.


I did combine the two, more or less.  The variable is_blank is set to
true within the constructor, when the provided letter is a space.
However, the get_is_blank query returns the value of is_blank, and not
whether letter is a space.  This keeps the two separate.  Note that
with DbC, we can put a contract on the constructor that keeps the input
to the constructor within the bounds [A..Z], or a space.

Right. That works fine in this simple example. But many contexts aren't that simple because there are multiple contexts for modifying state variables, either now or in future maintenance. The problem with the DbC approach is that one has to make an evaluation of whether there will be an inconsistency in the data _in every access context_ whenever there is a change to the way the data is modified. Sometimes that easy to prevent; other times it isn't.


Note that, in general, it isn't just where the data is modified. When Client.methodX just reads the value there is often a context that requires that changing the value must be synchronized with invoking Client.methodX (i.e., the value has to be changed by someone else before the invocation). That sort of timing constraint is difficult enough to get right with DbC without complicating it by adding a constraint that the dependent variable also be included in the precondition.

If one eliminates the dependency via normalization that complication is /never/ an issue so it doesn't even need to be considered during DbC analysis.

However, in more complex contexts it is not always so easy to know how
to bullet-proof consistency.  And regardless of how unlikely it is that
some future maintainer will add set_is_blank, it is not impossible.  So
we use Normal Formal to completely eliminate the possibility of an
inconsistency as simply a Good Design Practice.  (The maintainer can
obviously still muck things up, but will have to go to significant
trouble to do so.)  Then we never have to worry about whether we have
missed anything in the bullet-proofing for the problem in hand.  In
fact, we don't have to think about bullet-proofing this situation at all
once normalization is done.


How can this be done from within the code?  Remember, that's all a
future programmer might have.  I don't see what I have done as
bullet-proofing.  However, I am interested in how normalization is
manifested in code.

It is manifested by eliminating the dependent variable via normalization. In this case if Scrabble_Tile owns two attributes, is_blank and letter, then there is a dependency such that consistency between them must be evaluated in every access context. That is, in every client invocation context for access to either attribute one must ensure (a) the attribute accessed has been updated in a timely fashion AND (b) there is consistency between the attribute values.


Contrast that with when is_blank is simply a getter for the letter value. Now there is only one knowledge attribute and all one has to ensure is that is_blank returns the correct value corresponding to the /current/ value of letter. Then so long as the value of letter is synchronized to the invoking context the client will /always/ get the right answer. Now all one needs to ensure for any client invocation is that letter has been updated in a timely fashion.

Usually eliminating the dependent variable will have a nontrivial effect on the design. One way to do it is with your Wildcard. Another way was my distinguishing Rack_Tile from Scrabble_Tile and subclassing Rack_Tile. (That's not unprecedented because normalizing a Data Model very often requires adding tables.)

Alas, someone swiped my copy of OOSC just before I retired and I never
replaced it.  (As my blog indicates, it was an Epiphany for me in my
career.)  I don't recall whether Meyer explicitly talks about NF, but I
am quite sure that he provides guidelines for normalizing.  I am even
prepared to make a modest wager that he describes some rule or practice
that could be applied in the is_blank situation.


I'll have to look this up.  My copy of OOSC2 is in the back of a large
storage unit (due to a recent move), but I have the PDF version that
came with book.  I cannot recall this type of discussion in there, but
I think I know where to look.

Look for any context where he talks about redundancy in classes, attribute data domains, dependent variables, or attribute semantics. To resolve ambiguities in those sorts of things invariable requires some sort of normalization policy, whether is is called NF or not.


Maintenance problems are solved by including the contract with the
code.  I did my work in Eiffel, so it wasn't an issue.  It's right
there for a developer to see.  It is not implicit.

Eiffel assertions for contract enforcement are somewhat limited by the 3GL context. They can only define contracts from the service's perspective. As the developer or maintainer you have to devote design effort /manually/ to ensure that none of the clients violate service preconditions _in all possible collaboration contexts_. The goal of DbC is to ensure that the assertions /never/ get triggered in a correct program and that requires a lot of work.


I'm not sure I understand you here.  Contracts automatically enforce
clients to adhere to the rules in all collaboration contexts.  There is
no extra work needed to ensure that assertions do not get triggered, as
their triggering is automatic.

The operative word is 'enforce'. When you include correctness assertions they do rude things when the rules have been broken. That is, they enforce an /existing/ contract. The 'D' in DbC refers to the intellectual work the developer must do to (a) properly define contracts and (b) ensure that all clients comply with the contract preconditions in all possible execution contexts.


Those contracts are manifested in Eiffel by the existence of assertions. However, those assertions only define the contract from the service perspective; they describe the context for the service to do /its/ job. In particular, it is very difficult to define assertions that cover sequencing constraints _among clients_ invoking multiple service responsibilities. That's because those synchronization issues exist outside the service context.

The developer can still use DbC to resolve those issues (which is routine for interacting state machines in R-T/E) but the developer's thinking in doing so won't be documented for later maintainers. However, both the developer's and the maintainer's job will be easier if those synchronization issues are simpler. One easy way to ensure that is routine normalization to eliminate dependent attribute variables.


************* There is nothing wrong with me that could not be cured by a capful of Drano.

H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions  -- Put MDA to Work
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
(888)OOA-PATH



.



Relevant Pages

  • Re: Trouble with factory pattern
    ... the Factory itself goes and gets ... The former is most useful when the Context has all the necessary data, ... but only some of it is needed for each constructor. ... The specification object is useful when the decision data is not readily ...
    (comp.object)
  • Re: Trouble with factory pattern
    ... the Factory itself goes and gets ... The former is most useful when the Context has all the necessary data, ... but only some of it is needed for each constructor. ... The specification object is useful when the decision data is not readily ...
    (alt.comp.lang.learn.c-cpp)
  • Re: Trouble with factory pattern
    ... the Factory itself goes and gets ... The former is most useful when the Context has all the necessary data, ... but only some of it is needed for each constructor. ... The specification object is useful when the decision data is not readily ...
    (comp.lang.cpp)
  • Re: McLaren verdict
    ... don't have constructor points to worry about any more. ... contract" idea - as there's no constructors' points up for grabs, ... so there might be a certain amount of ... Whilst Alonso has looked bad in all this and my opinion of the guy is ...
    (rec.autos.sport.f1.moderated)
  • Re: base/derived name unhiding but with ctors
    ... Well, one problem with that terminology is that, when reading those parts ... of the standard that refer to constructor "calls", ... including large parts of the standard. ... of the subject matter (which is the normal context sensitivity of words) ...
    (comp.lang.cpp)