6.10 Type inference
Stan is strongly statically typed, meaning that the implementation type of an expression can be resolved at compile time.
The primitive implementation types for Stan are
int, real, vector, row_vector, matrix.
Every basic declared type corresponds to a primitive type; see the primitive type table for the mapping from types to their primitive types.
Primitive Type Table. The table shows the variable declaration types of Stan and their corresponding primitive implementation type. Stan functions, operators, and probability functions have argument and result types declared in terms of primitive types plus array dimensionality.
A full implementation type consists of a primitive implementation type
and an integer array dimensionality greater than or equal to zero.
These will be written to emphasize their array-like nature. For
array  real has an array dimensionality of 1,
array dimensionality of 0, and
array [,,] int an array dimensionality
of 3. The implementation type
matrix[ , , ] has a total of five
dimensions and takes up to five indices, three from the array and two
from the matrix.
Recall that the array dimensions come before the matrix or vector dimensions in an expression such as the following declaration of a three-dimensional array of matrices.
array[I, J, K] matrix[M, N] a;
a is indexed as
a[i, j, k, m, n] with the array
indices first, followed by the matrix indices, with
a[i, j, k]
being a matrix and
a[i, j, k, m] being a row vector.
Type inference rules
Stan’s type inference rules define the implementation type of an expression based on a background set of variable declarations. The rules work bottom up from primitive literal and variable expressions to complex expressions.
There are two promotion rules. First, integer expressions of type
int may be used anywhere an expression of type
real is used. An
integer is promoted to real by casting it in the underlying C++.
The second promotion rule is that expressions of type
real may be
used anywhere an expression of type
complex is required. A real
value is promoted to a complex number with that real component and a
zero imaginary component.
Promotion is transitive, so that integers may be promoted to complex numbers in two stages, first converting the integer to real, then converting the real value to a complex type.
An integer literal expression such as
42 is of type
Real literals such as
42.0 are of type
The type of a variable declared locally or in a previous block is
determined by its declaration. The type of a loop variable is
There is always a unique declaration for each variable in each scope because Stan prohibits the redeclaration of an already-declared variables.3
x is an expression of total dimensionality greater than or equal
to \(N\), then the type of expression
e[i1, ..., iN] is the same as
e[i1]...[iN], so it suffices to define the type of a
singly-indexed function. Suppose
e is an expression and
i is an
expression of primitive type
eis an expression of array dimensionality \(K > 0\), then
e[i]has array dimensionality \(K-1\) and the same primitive implementation type as
ehas implementation type
row_vectorof array dimensionality 0, then
e[i]has implementation type
ehas implementation type
f is the name of a function and
expressions for \(N \geq 0\), then
f(e1,...,eN) is an expression
whose type is determined by the return type in the function signature
eN. Recall that a
function signature is a declaration of the argument types and the
In looking up functions, binary operators like
real * real are
operator*(real, real) in the documentation and index.
In matching a function definition, arguments of type
int may be
promoted to type
real if necessary (see the subsection on type
promotion in the function application section for an exact
specification of Stan’s integer-to-real type-promotion rule).
In general, matrix operations return the lowest inferable type. For
row_vector * vector returns a value of type
real, which is declared in the function documentation and index
real operator*(row_vector, vector).
Languages such as C++ and R allow the declaration of a variable of a given name in a narrower scope to hide (take precedence over for evaluation) a variable defined in a containing scope.↩︎