3.2. Tuples

There are occasions, when returning a single value from a method does not suffice, or when it is tedious to have multiple method name parts just to have multiple arguments. TOM solves both problems through tuples.

A tuple is a group of values within parentheses, separated by commas. For instance, (1, 3.14) is a tuple. The type of a tuple is the tuple type of which the elements are the types of the elements of the tuple. The type of the example is (int, float).

An example of a method using tuples is the substring method from the String class.


String
  substring (int, int) (start, length);

This method has a single argument, the tuple (start, length). As with a lot of other String methods, this tuple is used to select a range of elements, starting at index start, and running for length elements, where a length of -1 means infinity.

The following example program, when run, will show a running text, probably best viewed on a slow terminal (of, say, 2400 baud).


int
  main Array argv
{
  OutputStream out = [stdio out];
  String text = "Testing...  1 2 3", spaces = "          ";
  int len = [spaces length], finish = len + [text length];
  int num = (![argv length] ? 100 : [argv[0] intValue]);
  int i, count;

  for (count = 0; count < num; count++)
    for (i = 0; i < finish; i++)
      {
        if (i < len)
          {
            /* Case 1: Spaces followed by start of text.  */
            [out print [spaces substring (0, len - i)]];
            [out print [text substring (0, i)]];
          }
        else if (i < finish - len)
          {
            /* Case 2: Start and end the line in the text.  */
            [out print [text substring (i - len, len)]];
          }
        else
          {
            /* Case 3: Text followed by spaces.  */
            [out print [text substring (i - len, finish - i)]];
            [out print [spaces substring (0, len - (finish - i))]];
          }
        /* Go back to the start of the line.  */
        [out print '\r'];
        [out flushOutput];
      }

  = 0;
}

As an example of a method returning a tuple, let's look at using an Enumerator. An Enumerator can be used to traverse a collection of objects. After asking the collection for an enumerator, the method


(boolean, Any)
  next;

can be used to repeatedly retrieve the next object. The value returned by next is a tuple with a boolean and an object. If the boolean is TRUE, the second element of the tuple contains the object retrieved. Otherwise, if it is FALSE, the end of the collection has been reached.

The following program is an example of using this method.


int
  main Array argv
{
  Enumerator e = [argv enumerator];
  Any object;

  while ({
           boolean valid;
           (valid, object) = [e next];
           valid;
         })
    [[[stdio out] print ("got one: `", object, '\'')] nl];

  return 0;
}

The example uses a compound expression as the condition of the while loop. This isn't just to show you this is possible; the tuple returned by next can not be used as a boolean condition, and the boolean must be repeated to give the compound its boolean value.

If the declaration of valid were not part of this compound (but put outside the while loop), the condition could be written as


while ({(valid, object) = [e next]; valid;})
  ...

which is the common notation.

In addition to providing multi-valued returns, and a compact method argument notation, tuples provide a sometimes desirable feature of simultaneous assignment. The most obvious application thereof is that of swapping the values of two variables:


(a, b) = (b, a);