Forward Compatibility

Mark Mitchell mark at codesourcery.com
Tue Sep 2 01:13:41 UTC 2003


One of the goals for QMTest 2.1 is to promise forward compatibility
for (at least a subset of) the QMTest APIs.  For example, we'd like to
say that a test class that satisfies such-and-such interfaces, and
uses only such-and-such other functionality in QMTest, is guaranteed
to work with all future versions of QMTest.

That will clearly make it easier for people to commit to using QMTest
for important projects.

To accomplish this goal, we must first say what it means to *be*
forward compatible; it's not entirely obvious.  Unfortunately,
defining this formally would require putting back on the formal
semantics that I wore in graduate school, and we'd end up with fifty
pages of theorems.  So, the definition will be necessary semi-formal.

Once we know what compatibility means, we'll have to audit various
interfaces in QMTest to satisfy ourselves that we can live with them
forever.  (Of course, we don't want to change them gratuitously, even
at this point, because there are already a lot of extension classes
relying on the current interface.)

Thoughts/comments on the attached?

--
Mark Mitchell
CodeSourcery, LLC
mark at codesourcery.com

Introduction

  The purpose of this document is to define the notion of "forward
  compatibility" for QMTest.  A QMTest user or extension class author
  can upgrade to a new version of QMTest if the new version is
  "forward compatible" with the old version.  This document defines
  this concept in more detail.

  The definition of forward compatibility relies on two key ideas:

  1. The user and/or extension class author must only rely on
     interfaces that have been specifically labeled as "compatible".
     An interface that is not so labeled may be changed freely.

     (Because no interface has been so labeled prior to QMTest 2.1,
     all versions of QMTest up to and including 2.0.3 have been
     vacuously forward compatible.)

     Any labeled interface may modify the requirements described below
     through its documentation.

  2. The definition for larger units (such as classes or modules) is
     built up from smaller units (such as variables or methods).

Functions

  A compatible function must not be removed.

  The names of the function parameters and the order in which they
  appear must not be altered.

  The values of default arguments must not change unless the new values
  have the same semantic implication as the old value.  (For example,
  a default value of '{}' could be changed to a default value of
  'None', if the new version of the function treated 'None' and '{}'
  interchangeably.)

  Parameter values that were previously valid (i.e., did not result in
  an error message or the raising of an exception) must not become
  invalid.  As an exception, if the previous behavior was incorrect,
  in that the function did not follow its documented and intended
  behavior, the previously valid parameter values may now be
  considered invalid.

  Parameter values that were previously invalid (i.e., resulted in an
  error message or raising an exception) may now be considered valid.

  New parameters may be added to a compatible function only if (a)
  they are placed at the end of the parameter list and (b) they have
  default values.

  A function may be replaced with a callable object, or vice versa.

Variables

  All compatible variables are read only.  User code must not attempt
  to modify a compatible variable.

  A compatible variable must not be removed.

  In general, the type of the variable must not change.  However, a
  value whose type is a superclass may be replaced with a value whose
  type is a subclass.  A value of a sequence type may be replaced with
  a value of another sequence type.

  A compatible variable whose value is a sequence type may contain
  additional elements in the sequence.  A compatible variable whose
  value is a dictionary type may add additional keys, or

Classes
 
  An old-style class may be replaced with a new-style class.

  All direct or indirect superclasses must be compatible.

  No direct or indirect superclass may be removed.  However, new super
  classes may be added.  A direct superclass may become an indirect
  superclass.

  All functions and variables in the class must be compatible, with
  two exceptions:

  1. A function or variable may be removed, if a compatible function
     is provided in a superclass.

  2. A function or variable whose name begins with two underscores
     need not be compatible.

  Two classes that were previous different may become the same class,
  provided that both names are still available.

Modules

  All functions, variables, and classes in a compatible module must be
  compatible, with two exceptions:

  1. A function, variable, or class whose name is not a public name in
     the sense defined by Python.  (See the Python documentation for
     "__all__" for a definintion of "public name".)

  2. A function, variable, or class whose name begins with two
     underscores need not be compatible.

File Formats

  A compatible file can be read by future versions of QMTest.



More information about the qmtest mailing list