3. Types
Every Capy value has a type. The compiler checks types before the program runs. It usually infers the type of a local value.
Integers
An integer literal has type s64 when no other type is stated:
function RENDER(request : dval) {
var answer := 42
print(answer, "\n")
}
Output
42
State the type on the local, or construct the value explicitly:
function RENDER(request : dval) {
var signed : s64 = 8
var inferred_signed := s64(9)
var unsigned : u64 = 10
var inferred_unsigned := u64(11)
print(signed, " ", inferred_signed, " ", unsigned, " ", inferred_unsigned, "\n")
}
Both forms produce the stated integer type. var signed : s64 = s64(8) also compiles, but the constructor repeats the annotation.
Parameters, function results, assignments, typed arrays, struct fields, and the other operand in an expression can also state the integer type. Thus, a function that accepts u64 can receive the plain literal 8. An unconstrained literal remains s64.
Arithmetic requires operands of the same type. Use a constructor when the surrounding code does not state the required type.
Booleans and floating-point numbers
A bool is either true or false. Conditions require a boolean value.
function RENDER(request : dval) {
var enabled := true
var ratio := 2.5
print(enabled, " ", ratio, "\n")
}
A decimal point or exponent makes an f64 literal.
Strings
A string stores bytes:
function RENDER(request : dval) {
var name := "Ada"
var empty := ""
print(name, empty, "\n")
}
An empty string is still a string value. It is not missing data.
Arrays and structs
An array contains values of one type:
function RENDER(request : dval) {
var names := ["Ada", "Grace"]
print(names[0], "\n")
}
A struct gives names to fixed fields:
struct Point {
x : s32
y : s32
}
function RENDER(request : dval) {
var point := Point(3, 4)
print(point.x, " ", point.y, "\n")
}
Arrays and struct instances are mutable reference values inside one workspace. Assignment shares their identity.
The collections chapter covers these types in detail.
Numeric functions
Use the math functions for floating-point calculations and numeric bounds. Use the bits functions for integer masks, shifts, rotations, counts, and bit reinterpretation.
See the math function reference for floating-point operations and predicates. See the bits function reference for integer bit operations and floating-point bit reinterpretation.
Dynamic values and none
A dval holds data whose shape is known only at run time. The none value represents missing dynamic data:
function RENDER(request : dval) {
var profile := {name: "Ada"}
var missing := none
print(profile.name, " ", missing?, "\n")
}
none is different from "", false, an empty map, and an empty list. A dval is also a mutable reference value inside one workspace. The dynamic-values chapter explains mutation, safe reads, and conversions.
Type aliases and static type names
A type alias gives another name to a type. It does not create a distinct type at runtime.
Use expression::type_name to get the resolved static type of an expression. Capy evaluates the expression once.
type Count = s64
function RENDER(request : dval) {
var total : Count = 12
var labels := ["new", "done"]
print(total::type_name, " ", labels::type_name, "\n")
}
Output
s64 [string]
An alias reports its target type. Arrays use [item_type]. Structs use their declared name. Function values use their complete function type.
A dval expression reports dval, regardless of its current contents. Use get_type_name(value) to inspect the value stored inside a dval.
Struct field inspection
Struct values have two additional reflection expressions:
| Expression | Result | Meaning |
|---|---|---|
value::size | s64 | The number of declared fields. This is not a byte size. |
value::items | dval | A snapshot of the current fields, keyed by field name. |
Each items entry contains value and type_name. Use fields.name.value for a fixed field. Use fields[key]["value"] for a dynamic field name.
value::items evaluates its receiver once. Changing the returned map does not change the struct. The compiler rejects size and items on non-struct values.
The struct reference defines field conversions for scalars, strings, DValues, nested structs, arrays, and function values.
Dependent generic types
A generic function can use the concrete type of an earlier any parameter. Write parameter::type in a later parameter or the function result:
function same(first : any, second : first::type) first::type {
-> second
}parameter::type is a compile-time type expression. It does not inspect a runtime value. The compiler rejects the removed type(parameter) spelling.