S
Steven T. Hatton
E. Robert Tisdale said:Steven T. Hatton wrote:
Yes. The invariant is trivial.
And I think that your understanding of invariance is consistent
with the way that Stroustrup uses the term.
Notice that, in the example above, there is no way to construct
an invalid SocialSecurityNumber and no assignment is defined
except the default assignment from another valid SocialSecurityNumber.
Ironically, your SSN is very close to a class I created while playing around
with developing an OO parser/validator for C++. My class is Identifier.
/***************************************************************************
* Copyright (C) 2004 by Steven T. Hatton *
* (e-mail address removed) *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef STH_CLASSBUILDERIDENTIFIER_H
#define STH_CLASSBUILDERIDENTIFIER_H
#include <string>
#include <cctype>
#include "InvalidIdentifier_Exception.h"
namespace sth
{
namespace ClassBuilder
{
/**
@author Steven T. Hatton
*/
class Identifier
{
public:
Identifier();
Identifier(const std::string& value_)
throw(InvalidIdentifier_Exception);
~Identifier();
/**
* Convenience function to support input validation.
* @param c
* @return
*/
static bool is_valid_char(const char& c)
{
return isalnum(c) || c == '_';
}
/**
* Convenience function to support input validation.
* @param c
* @return
*/
static bool is_valid_first_char(const char& c)
{
return Identifier::is_valid_char(c) && !isdigit(c);
}
static bool is_valid(const std::string& s);
operator std::string()
{
return this->value;
}
private:
std::string value;
};
};
};
#endif
#include "Identifier.h"
namespace sth
{
namespace ClassBuilder
{
Identifier::Identifier()
{}
Identifier::Identifier(const std::string& value_)
throw(InvalidIdentifier_Exception)
: value(value_)
{
if(!is_valid(this->value))
{
throw InvalidIdentifier_Exception();
}
}
Identifier::~Identifier()
{}
}
;
};
/*!
\fn sth::ClassBuilder::Identifier::is_valid(const std::string& s)
*/
bool sth::ClassBuilder::Identifier::is_valid(const std::string& s)
{
if((s.length() == 0) || !is_valid_first_char(s[0]))
{
return false;
}
for(size_t i = 1; i < s.length(); i++)
{
if(!is_valid_char(s))
{
return false;
}
}
return true;
}
I finally realized what I am really questioning is the relationship between
things like property lists and the concept of invariants. I had already
come to the conclusion that it is reasonable for a class to have some
invariants which are preserved under a given set of operations. For
example, a rectangle should preserve its right angles an side lengths under
translations and rotations. But the length of the sides would likely be
adjustable under other operations. A subset of these operations could be
defined so that the ratios of the side lengths are preserved.
I don't know exactly what Stroustrup's position is on that aspect of
invariance. This is the article that really helped me understand what he
was getting at with invariants.
http://www.research.att.com/~bs/eh_brief.pdf
Consider this list of properties describing a simple box that displays text
with specified colors, size, shape and location, as well as some other
information about its role in a collection of other objects of this class:
bool is_leaf;
bool is_vertical;
std::string text;
RgbColor bg_color;
RgbColor text_color;
RgbColor edge_color;
double h;
double w;
double border_w;
double x;
double y;
int bg_z;
int text_z;
The data members were not chose because I recognized an invariant and
identified them as essential in maintaining that invariant. They were
chosen because they are what I need in order to implement my design, and
they are all essential to the one aspect of the program which involves
presenting the computed results. The variables such as RgbColor type
members are designed to preserve their own invariants. And that invariance
is a result of using unsigned char for the member data. RgbColor is a
struct.
One thing I've been wondering about is the notion of distributed invariants.
That is, in the case of my property objects, it has become reasonable to
employ an observer pattern that involves notifying some objects that the
properties have changed. Looking at the data I have listed above, it seems
fairly orthogonal. Any one member can be changed without modifying the
others. The one exception is that the text position needs to be calculated
when any of the other geometric data is modified.
There is, however a requirement that different objects in the system remain
synchronized with the state of the properties object. I'm wondering how
useful it is to extend the notion of class invariants to a notion of
distributed state with multiple participants.