Go to the first, previous, next, last section, table of contents.


6.1.8.1 Sorts for Formal Parameters

The sort of an identifier depends on how it is declared. If it is declared as a global variable, then its sort is given by its declaration (see section 5.4 Declarators). If it is a constant from a trait, then its sort is given in the trait. If an identifier declared in a quantifier, then the declaration explicitly gives its sort. Otherwise, for identifiers declared as formal parameters, the sort is determined from the declared type (see section 2.7 Types and Sorts) as for global variables (see section 5.4 Declarators) with the following important differences. The first difference is that since parameters are passed by value, the leading Obj sort generator (or ConstObj generator, see below) is taken off, unless the type is a reference type. The reason for taking off the leading Obj sort generator is that non-reference parameters are passed by value in C++. (In this we follow LCL, see [Guttag-Horning93].) Second, the use of array types for formal parameters (at the top level) is equivalent to the use of a pointer type. (This follows C++, but differs from LCL [Chalin95].) Finally, the sorts of formal struct and union parameters are the corresponding value sort, not the object sort. Examples are given in the following table.

Declaration      VarId   Its Sort (when used as a formal parameter)
-------------    -----   -----------------------------------------
int i            i       int
int & ir         ir      Obj[int]
int * ip         ip      Ptr[Obj[int]]
int ai[]         ai      Ptr[Obj[int]]
struct IPair {
  int fst, snd;
  };
IPair sip;       sip     Val[IPair]
union FI {
  float f;
  int i;
  };
FI fi;           fi      Val[FI]

In the table above, the sorts of ir and i differ, unlike the case for global variables. The sort of *ip is Obj[int], which is also the sort of: ai[0], ip[0], and *ai.

The sort of ai is the same as the sort of ip, because of the C++ equivalence between array parameters and pointer parameters. Another way to think of this is that when an array is passed in C++, the address of the element with index 0 is passed as a pointer value. (Although in C++ there is no type distinction between an array name and a pointer value, so that myArray and &myArray[0] are equivalent in almost all contexts; in the Larch/C++ model these two expressions have different sorts, and thus one should think of the C++ function call f(myArray) as shorthand for f(&myArray[0]). In terms of the trait functions of the trait PrePointer (see section 11.8 Pointer Types), the abstract value passed is address_of(myArray,0).)

The sort of sip is not IPair, but Val[IPair], because IPair would be a tuple of objects instead of a tuple of values (see section 11.10 Structure and Class Types). The sort Val[IPair] is a tuple with two fields, fst and snd, both of sort int (not Obj[int], but int values). This models passing structures by value. Hence the sort s of the terms sip.fst and sip.snd are both int.

Similarly, the sort of fi is not FI, but Val[FI], since pass by value implies the formal parameter's model should be a union of values (not objects). The sort Val[FI] is a union with two tags: f and i. When defined, the sort of fi.f is float, and the sort of fi.i is int. See section 11.11 Union Types for details on how the sort Val[FI] is defined.

Except for reference parameters, the use of const does not change the sorts of formal parameters. It also does affect the C++ interface of a function, unless one uses const reference, pointer, or array parameters [ANSI95]. Hence its use is best avoided for formal parameters, except, of course for const reference, pointer, or array parameters. The sort of a formal parameter that uses const is derived from the sort of the corresponding global variable declaration in a way that is analogous to how the sorts of formals without const are derived. That is, the main idea is that the leading ConstObj sort generator is taken off of the sort of the corresponding global variable declaration, but this does not affect reference parameters. For example, consider the following.

Declaration            VarId   Its sort (when used as a formal parameter)
-------------------    -----   -----------------------------------------
const int ci           ci      int
const int& rc          rc      ConstObj[int]
int& const cr          cr      ConstObj[int]
const int * pci        pci     Ptr[ConstObj[int]]
int * const cip        cip     Ptr[Obj[int]]
const int cai[]        cpi     Ptr[ConstObj[int]]
struct IPair {
  int fst, snd;
  };
const pair csip;       csip    Val[IPair]

In the above, the sorts of the references are the same as they would be when used as global variables. The sort of pci reflects its being a pointer to constant integer objects. Thus pci, used as a formal parameter, is considered to name a value, but *pci is an lvalue--a constant integer object. The sort Val[IPair] is a tuple of two fields fst and snd, both of sort int. See section 11.10 Structure and Class Types for details on this sort.

C++ considers the declarations int and const int different for formal parameters, and thus for linking programs with functions so declared. When possible, avoid the use of const for such formals, and only use it for references and pointers (and for pointers, only in the form as shown in the declaration of pci).

For C++ type names T and S, the above discussion is summarized in the following table. See section 11.10 Structure and Class Types for an explanation of how the sort Val[STS] is defined.

Form of Decl.  Sort of x (used as a formal parameter)
-------------  --------------------------------------
T x            T
const T x      T
T & x          Obj[T]
const T & x    ConstObj[T]
T & const x    ConstObj[T]
T * x          Ptr[Obj[T]]
const T * x    Ptr[ConstObj[T]]
T * const x    Ptr[Obj[T]]
T x[]          Ptr[Obj[T]]
const T x[]    Ptr[ConstObj[T]]
struct STS {
  T t; S s
  };
STS x;         Val[STS]
const STs x;   Val[STS]

When these types are composed, the sort becomes the composite of the sorts given. The only apparent exception is the interaction of const and references. The following are a few examples. See section 11.10 Structure and Class Types discusses how the traits that define Val[Str] and Val[IntList] would be defined. Note that Val[IntList] is a tuple of two fields. The field val has sort int, and the field next has sort Ptr[Obj[IntList]]. See section 5.4.8 Summary of Declarations to compare the following with the sorts of the corresponding global variables.

Declaration             Sort of x (used as a formal parameter)
-------------           --------------------------------------
const int &const x;     ConstObj[int]
const int *const x;     Ptr[ConstObj[int]]
const int x[][4];       Ptr[Arr[ConstObj[int]]]
int *x[];               Ptr[Obj[Ptr[Obj[int]]]]
int **x;                Ptr[Obj[Ptr[Obj[int]]]]
int (*x)[10];           Ptr[Arr[Obj[int]]]
int (*x[])[4];          Ptr[Obj[Ptr[Arr[Obj[int]]]]]
int *const x[];         Ptr[ConstObj[Ptr[Obj[int]]]]
int ***x;               Ptr[Obj[Ptr[Obj[Ptr[Obj[int]]]]]]
struct Str {
  char *s;
  int len;
  };
Str x;                  Val[Str]
struct IntList {
  int val;
  IntList *next;
  };
IntList x;              Val[IntList]
const IntList x;        Val[IntList]


Go to the first, previous, next, last section, table of contents.