Next / Previous / Contents / Shipman's homepage

5.8. Specification functions

In Section 5.7, “The “let” convention” we showed how it can make intended functions shorter or clearer by using shorthand names for lengthy phrases.

This sort of shorthanding can also be useful when the same phrase occurs in different intended functions of the same program. Following Stavely, the author calls these shorthand notations specification functions.

Because they are purely for notation purposes, and not part of the actual code, the author prefers to define each specification function in a comment, generally all together and alphabetized for easy lookup.

Here is an example. Python's built-in sorted() function returns a list containing the elements of an iterable in some specified ordering. The prototype looks like this:

sorted(sequence[, cmp=None[, key=None[, reverse=None]]])
sequence

The sequence to be sorted, any Python iterable.

cmp

If provided, this is a function that defines the ordering. It must accept two arguments and return a negative number if the first argument is to be considered less than the second; zero, if they are to be considered equal; or a positive number if the first is greater.

key

If provided, this is a function that defines the key to be used in sorting (the default is to use the elements themselves). It takes one argument, whose type is the type of the elements of the sequence, and returns a value that may be of a different type, which we will call the key domain.

If both cmp and key functions are provided, the cmp() function must operate on values in the key domain.

If no key function is provided, the cmp() function operates on the type of the elements of sequence.

reverse

If this argument is true, the result is in the reverse order of the ordering specified by the other arguments.

An honest intended function for the sorted() function must describe, among other things, two interfaces: the interface to the function passed to the cmp argument, and the interface to the function passed as the key argument.

To solve this problem, the author would define two specification functions describing these two interfaces. The author also uses a specific typographic convention for their names: each is made of two or more words connected with hyphens. This clearly distinguishes them from Python names, since they are never used in actual code anyway.

  #================================================================
  # Specification functions
  #----------------------------------------------------------------
  # comparator-function ==
  #   a function whose signature is
  #     f(x, y)
  #   and whose intended function is
  #     [ if x < y ->
  #         return a negative number
  #       else if x == y ->
  #         return 0
  #       else ->
  #         return a positive number ]
  #----------------------------------------------------------------
  # key-function ==
  #   a function of one argument that returns a single value
  #----------------------------------------------------------------

Then we can write the intended function for sorted() like this.

  [ (sequence is an iterable) and
    (cmp is a comparator-function, defaulting to the built-in
    Python cmp() function)) and
    (key is a key-function, defaulting to the identity function) ->
      if bool(reverse) ->
        return a list containing the elements of sequence,
        ordered using cmp(key(x),key(y)) for any pair x,y,
        in descending order
      else ->
        return a list containing the elements of sequence,
        ordered using cmp(key(x),key(y)) for any pair x,y,
        in ascending order ]

As always, consider your audience when writing intended functions. The above example presupposes that the reader understands a little about how generic sort functions work, and that the ordering they produce is ultimately defined by a mechanism to compare two arbitrary values.

You may also use specification functions to define shorthand names as discussed in Section 5.7, “The “let” convention”.

You may also use parameterized specification functions. These use standard functional notation. For example:

#--
# ref-key(ref) == ref.word + "|" + ref.suffix + "|" + ref.prefix
#--
# The key value used to order one reference to a keyword, where
# ref is an instance of the KwicRef class.
#--

This is taken from kwic.py: A Python module to generate a Key Word In Context (KWIC) index. The ref-key specification function describes how instances of a certain class are ordered according to the concatenation of three attributes of the instance, separated by vertical bars.