Skip to content

Types

Nic has a rich type system with primitives, compound types, and user-defined types.

Primitive Types

Integers

Signed and unsigned integers of various sizes:

nic
fn main() -> unit {
    // Signed integers
    let a: i8 = -128;
    let b: i16 = -32768;
    let c: i32 = -2147483648;
    let d: i64 = 9223372036854775807;
    let e: i128 = 0;
    
    // Unsigned integers
    let f: u8 = 255;
    let g: u16 = 65535;
    let h: u32 = 4294967295;
    let i: u64 = 18446744073709551615;
    let j: u128 = 0;
    
    return;
}

Floats

nic
fn main() -> unit {
    let x: f32 = 3.14;
    let y: f64 = 2.718281828;
    let z: float = 1.0;  // 'float' is an alias for f64
    
    return;
}

Other Primitives

nic
fn main() -> unit {
    let flag: bool = true;
    let letter: char = 'A';
    let message: string = "Hello";
    let nothing: unit = ();  // unit type, like void

    return;
}

String Interpolation

Embed expressions directly in strings using ${} syntax:

nic
fn main() -> unit {
    let name = String.from("World");
    defer release name;

    // String interpolation with *String
    let greeting = "Hello, ${name}!";
    defer release greeting;
    puts(greeting.to_literal());  // Hello, World!

    // Integer interpolation
    let x = 10;
    let y = 20;
    let msg = "Sum of ${x} and ${y} is ${x + y}";
    defer release msg;
    puts(msg.to_literal());  // Sum of 10 and 20 is 30

    // Escape $ with $$
    let price = "Price: $$99";  // plain string: Price: $99
    puts(price);

    return;
}

Key points:

  • Strings with ${} return *String (heap-allocated, must be released)
  • Strings without ${} remain as string (C string literal, no release needed)
  • Supported types inside ${}: *String, string, and integer types
  • Escape a literal $ by doubling it: $$

Numeric Literals

nic
fn main() -> unit {
    let decimal: i32 = 42;
    let hex: i32 = 0x2A;
    let octal: i32 = 0o52;
    let binary: i32 = 0b101010;
    let float_val: f64 = 3.14;
    let scientific: f64 = 1.5e-10;
    
    return;
}

Arrays

Fixed-size arrays with compile-time known length:

nic
fn main() -> unit {
    // Array of 5 integers
    let arr: [5]i32;
    arr[0] = 10;
    arr[1] = 20;
    arr[2] = 30;
    arr[3] = 40;
    arr[4] = 50;
    
    // Array literal
    let nums: [3]i32 = [1, 2, 3];
    
    return;
}

Slices

Dynamic views into arrays:

nic
fn sum(numbers: []i32) -> i32 {
    let total: i32 = 0;
    // ... iteration logic
    return total;
}

Array Slicing

Extract portions of arrays using range syntax:

nic
fn main() -> unit {
    let arr: [5]i32 = [1, 2, 3, 4, 5];

    // Exclusive range: elements at indices 1, 2
    let middle = arr[1..3];  // [2, 3]

    // Inclusive range: elements at indices 1, 2, 3
    let more = arr[1..=3];   // [2, 3, 4]

    // From start: first 3 elements
    let first = arr[..3];    // [1, 2, 3]

    // To end: from index 2 onwards
    let last = arr[2..];     // [3, 4, 5]

    // Full slice: entire array
    let all = arr[..];       // [1, 2, 3, 4, 5]

    return;
}

Slice Syntax Summary

SyntaxDescription
arr[start..end]Elements from start to end-1 (exclusive)
arr[start..=end]Elements from start to end (inclusive)
arr[..end]Elements from 0 to end-1
arr[start..]Elements from start to last
arr[..]All elements

Tuples

Group multiple values of different types:

nic
fn main() -> unit {
    let pair: (i32, string) = (42, "answer");
    let triple: (i32, f64, bool) = (1, 2.0, true);
    
    // Access via destructuring
    let (x, y) = pair;
    let (a, b, c) = triple;
    
    return;
}

Pointers and References

nic
fn main() -> unit {
    let x: i32 = 42;
    
    let ptr: *i32 = &x;   // pointer to x
    let ref_x: &i32 = &x; // reference to x
    
    let value: i32 = *ptr; // dereference
    
    // Null pointer
    let null_ptr: *i32 = nil;
    
    return;
}

Type Casting

Use as for explicit type conversions:

nic
fn main() -> unit {
    let x: i32 = 42;
    let y: i64 = x as i64;      // widening
    let z: i32 = y as i32;      // narrowing
    
    let f: f64 = x as f64;      // int to float
    let i: i32 = 3.7 as i32;    // float to int (truncates to 3)
    
    let b: bool = true;
    let bi: i32 = b as i32;     // bool to int (1)
    
    return;
}

Platform Types (C FFI)

For C interoperability:

nic
fn main() -> unit {
    let size: size_t = 1024;
    let diff: ptrdiff_t = 0;
    let addr: uintptr_t = 0;
    
    return;
}

Type Summary

CategoryTypes
Signed integersi8, i16, i32, i64, i128
Unsigned integersu8, u16, u32, u64, u128
Floatsf32, f64, float
Otherbool, char, string, unit
Compound[N]T, []T, (T, U), *T, &T
Platformsize_t, ssize_t, intptr_t, uintptr_t, ptrdiff_t

Next

Learn how to write Functions with these types.

Released under the MIT License.