Documentation Index
Fetch the complete documentation index at: https://sdk.cerebras.ai/llms.txt
Use this file to discover all available pages before exploring further.
Overview
CSL’s type system does not have a notion of generic types like that of C++ or Java. Instead, generic programming is achieved through CSL’s comptime features. The basic idea is thattype is a type, with values such as i16, i32,
bool, and so on, and one can perform computation using types at
comptime.
A very simple generic function looks something like:
type is a comptime-only type just like comptime_int,
comptime_float, or comptime_string, T must be marked comptime
in order to appear as the type for x and as the function’s return type.
CSL’s generics resemble C++ templates in some ways. Generic functions are
monomorphized by the compiler. This means a generic function does not exist at
runtime; instead, a copy of the function is compiled using each set of type
arguments it is called with. The program will compile as long as each such copy
is well-formed. An implication is that, for instance, a generic function that
uses the unary - operator will not compile if it is called with a type like
comptime_string that cannot be used with unary -:
anytype
While explicitly passing a parameter of typetype to a generic function is
a straightforward mechanism, it can be verbose. For the user of a library that
provides an abs function, there is not much benefit to writing
abs(f32, 1.0 - x) versus a non-generic equivalent of abs_f32(1.0 - x).
The anytype keyword provides a solution.
anytype can only appear as the type of function parameters. It is another
way to write a generic function and it has the same effect of creating a
version of the function for each type that it is called with. When declaring
parameters with anytype, the @type_of builtin is useful to relate the
types of parameters and the return value to each other:
types as generic functions:
Point above is a function that takes a type parameter and
returns a struct parameterized by that type.
Constraining Type Parameters
If a generic function is called with an invalid type, an error occurs when the compiler discovers that the generic function’s body is trying to do something invalid with its argument. This is typically a lower-level error than the actual mistake of calling the function with an incorrect argument type:abs were a
more complicated function, the mistake will be less obvious. Programmers who
have used C++ templates may find this situation familar.
Instead, the function can test the provided type and fail a
comptime assertion if it is invalid:
Specializing Logic
A related scenario is writing a generic function where a portion of the logic is only valid for some of the types over which one wants to define the function. Consider the example ofsign from the <math> library. This
function returns -1 if its argument is negative, 1 if it is positive,
and 0 if it is zero. sign could naïvely be written like:
math.sign allows x to be an unsigned integer. While
sign(<some u16>) is not quite as interesting as sign of a float or
signed integer, it is perfectly valid to allow. However, the above code would
not compile if passed a u16 because -1 is not a valid u16.
To solve this problem, guard the if (x < 0) case with a check for
the argument type:
if condition at comptime ensures that the if (x < 0)
case is only compiled at all if the type is correct.
There is one final change that needs to be added to properly support floats:
1 and 0 are comptime_ints, they do not automatically
convert to floats.
Computing With Types
As the previous use of@type_of alludes to, type specifiers can be any
expression that has type type:
@comptime_asserts in helper functions also take care of
validating that the type parameter is a float.
<math> library internally uses this pattern to generically implement
IEEE floating point functions like isNaN, isInf, and even ceil and
floor.
