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)

throw exception on access of an invalid object (source)

Interface

void AccessInvalidFallibleObject()

Description

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

void AccessInvalidFallibleObject()


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

Description

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)

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)

~Fallible()

operator T() const

Automatically convert a Fallible<T> to a T.

T value() const

Sometimes it's more convenient to not rely on a compiler supplied conversion, especially when the compiler is confused.

Bool isValid() const