Fallible.h
Classes
- Global Functions -- throw exception on access of an invalid object (full description)
- Fallible -- Mark a value as valid or invalid. (full description)
Interface
- void AccessInvalidFallibleObject()
This function gets called when an invalid object is accessed. It
just throws an exception. Since we have inline functions, let's keep
the throw out of them to keep them from moving out of line.
Thrown Exceptions
Member Description
template<class T> class Fallible
Interface
- Public Members
- Fallible() : isValid_p(False)
- Fallible(const T &value) : value_p(value), isValid_p(True)
- Fallible(const Fallible<T> &other) : value_p(other.value_p), isValid_p(other.isValid_p)
- Fallible<T> &operator=(const Fallible<T> &other)
- ~Fallible()
- operator T() const
- T value() const
- Bool isValid() const
Review Status
- Reviewed By:
- Gareth Hunt
- Date Reviewed:
- 1994/09/14
- Programs:
- Tests:
Etymology
This is to be used for values which might be fallible, i.e. might not
be valid.
Synopsis
This class resembles the one in Scientific and Engineering C++
by Barton and Nackman. While it was written with that book closed, the
class is simple enough that resemblances likely remain.
This class essentially just holds a value (with automatic conversion)
and allows inquiry as to whether the value is valid. If the value is
used and is indeed invalid an exception will be thrown.
A copy of the value is stored in the Fallible<T> object, so
making copies shouldn't be too expensive. It is anticipated that this
class will most often be used with built in, or other small, types.
Example
Suppose we write some code that turns a day/month/year into a day
of the week:
enum DayName {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday,
Saturday};
Fallible<DayName> dayFromDate(uInt day, uInt month, uInt year); // a func.
And we also have some other function that needs a day name, for example
just prints it:
ostream &operator<<(ostream &os, DayName day); // Print name as string
Since the automatic conversions are defined, if we are certain that the
dates are valid, we can just go ahead and use the value:
cout << dayFromData(2, 1, 1962) << endl; // A valid date
If, by some chance, you are wrong and a date fails, then an exception will
be thrown and a run-time error will occur.
If, as is more likely the case, you don't know a priori whether a test will
succeed, you can check it:
Fallible<DayName> result = dayFromDate(d,m,y); // who knows if valid?
if (result.isValid()) {
cout << result << endl;
} else {
// some corrective action
}
Motivation
The alternatives are to have "special values" (e.g. have an "undefined
day" in the enumeration) or return a Boolean, or change a Boolean. While
those solutions are often adequate, Fallible<T> can often be
more natural.
Template Type Argument Requirements (T)
- default constructor
- copy constructor
Member Description
Fallible() : isValid_p(False)
The default constructor creates an invalid object.
Fallible(const T &value) : value_p(value), isValid_p(True)
Create a valid object
Fallible(const Fallible<T> &other) : value_p(other.value_p), isValid_p(other.isValid_p)
Fallible<T> &operator=(const Fallible<T> &other)
operator T() const
Automatically convert a Fallible<T> to a T.
Sometimes it's more convenient to not rely on a compiler supplied
conversion, especially when the compiler is confused.