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 infinity
  • nan - 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
\nNewline
\tTab
\"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]
→ Learn more about arrays

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

→ Learn more about tuples

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
→ Learn more about tensors

Next Steps