Types
Charl is a statically-typed language with type inference. Every value has a specific type known at compile time.
Type Overview
| Type | Description | Example |
|---|---|---|
| int | Integer numbers | 42, -17, 0 |
| float | Floating point numbers | 3.14, -0.5, 2.0 |
| bool | Boolean values | true, false |
| string | Text strings | "hello" |
| [T] | Array of type T | [1, 2, 3] |
| (T1, T2, ...) | Tuple | (42, "hello") |
| Tensor | Multi-dimensional array | tensor([1.0, 2.0]) |
Primitive Types
int
64-bit signed integer. Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
let x: int = 42
let y: int = -17
let z: int = 0
// Large numbers
let big: int = 1000000000
// Integer arithmetic
let sum: int = x + y
let product: int = x * 2
Note: Integer operations that overflow will wrap around. Be careful with large computations.
Common Operations
- Arithmetic:
+,-,*,/,% - Comparison:
==,!=,<,<=,>,>= - Conversion to float: implicit in mixed operations
float
64-bit floating point number (IEEE 754 double precision)
let pi: float = 3.14159
let e: float = 2.71828
let neg: float = -0.5
// Scientific notation
let small: float = 1.0e-5 // 0.00001
let large: float = 1.0e10 // 10000000000.0
// Float arithmetic
let result: float = pi * 2.0
let ratio: float = pi / e
Precision: Floats have ~15-17 decimal digits of precision. Be aware of rounding errors in comparisons.
Special Values
inf- Positive infinity (from overflow or division by zero)-inf- Negative infinitynan- Not a number (from invalid operations like 0/0)
bool
Boolean type with two values: true and false
let is_active: bool = true
let is_complete: bool = false
// From comparisons
let greater: bool = 5 > 3 // true
let equal: bool = 10 == 10 // true
let not_equal: bool = 5 != 3 // true
// Logical operations
let and_result: bool = true && false // false
let or_result: bool = true || false // true
let not_result: bool = !true // false
Logical Operators
| Operator | Name | Example |
|---|---|---|
| && | AND | true && false → false |
| || | OR | true || false → true |
| ! | NOT | !true → false |
string
UTF-8 encoded text strings
let message: string = "Hello, World!"
let name: string = "Charl"
let empty: string = ""
// String concatenation
let greeting: string = "Hello, " + name + "!"
// Multiline strings (no special syntax, use \n)
let multiline: string = "Line 1\nLine 2\nLine 3"
// Escape sequences
let quote: string = "He said \"Hello\""
let backslash: string = "Path: C:\\Users\\Name"
Escape Sequences
| Sequence | Meaning |
|---|---|
| \n | Newline |
| \t | Tab |
| \" | Double quote |
| \\ | Backslash |
Compound Types
Arrays
Fixed or dynamic-sized collections of elements of the same type
// Array of integers
let numbers: [int] = [1, 2, 3, 4, 5]
// Array of floats
let prices: [float] = [9.99, 19.99, 29.99]
// Array of strings
let names: [string] = ["Alice", "Bob", "Charlie"]
// Nested arrays
let matrix: [[int]] = [[1, 2], [3, 4], [5, 6]]
// Type inference
let inferred = [1.0, 2.0, 3.0] // Inferred as [float]
Array operations:
- Access:
arr[0] - Length:
len(arr) - Slicing:
arr[1..3]
Tuples
Fixed-size collection of values of different types
// Pair of int and string
let pair: (int, string) = (42, "answer")
// Triple
let triple: (float, float, float) = (1.0, 2.0, 3.0)
// Mixed types
let mixed: (int, string, bool, float) = (1, "hello", true, 3.14)
// Accessing tuple elements
let first = pair.0 // 42
let second = pair.1 // "answer"
// Nested tuples
let nested: ((int, int), string) = ((1, 2), "coords")
Use case: Return multiple values from functions without creating a struct
Type Inference
Charl can automatically deduce types from context, reducing verbosity while maintaining type safety.
// These two are equivalent:
let x: int = 42
let x = 42 // Type inferred as int
// Inference from operations
let y = 3.14 // float
let z = true // bool
let s = "hello" // string
let arr = [1, 2, 3] // [int]
// Inference in function returns
fn double(x: int) {
return x * 2 // Return type inferred as int
}
// Complex inference
let result = tensor([1.0, 2.0, 3.0]) // Inferred as Tensor
Best practice: Use explicit types for function parameters and public APIs. Use inference for local variables when the type is obvious.
Type Conversion
Charl does not perform implicit type conversions. You must explicitly convert between types.
// Int to float
let i: int = 42
let f: float = float(i) // Explicit conversion
// Float to int (truncates)
let f2: float = 3.7
let i2: int = int(f2) // i2 = 3
// Number to string
let num: int = 123
let s: string = str(num) // "123"
// Bool to string
let b: bool = true
let bs: string = str(b) // "true"
Error: Mixing types without conversion will cause a compile error
let x: int = 42
let y: float = 3.14
let z = x + y // ERROR: Cannot add int and float
Tensor Type
Tensors are multi-dimensional arrays optimized for machine learning operations.
// Create 1D tensor
let v = tensor([1.0, 2.0, 3.0])
// Create 2D tensor via reshape
let matrix_data = tensor([1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
let matrix = tensor_reshape(matrix_data, [2, 3])
// Shape: [2, 3]
// [[1.0, 2.0, 3.0],
// [4.0, 5.0, 6.0]]
// Initialize with zeros
let weights = tensor_zeros([128, 64])
// Random initialization
let random_weights = tensor_randn([784, 10])
Tensor operations are optimized for:
- Vectorized computations
- Matrix operations (BLAS)
- Automatic differentiation
- GPU acceleration