Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Language Overview

Chemical is a native, statically‑typed programming language designed to be safe and easy to use while giving developers low‑level control. If you’re familiar with languages like TypeScript, Rust, or C, many of Chemical’s constructs will feel familiar.

This chapter provides a concise guide to Chemical’s core syntax and features, including:

  • Variable and constant declarations

  • Primitive and compound types

  • Functions and generics

  • Comments and documentation

  • Control‑flow constructs

  • Enumeration and variant types

  • Data structures: arrays, structs, and interfaces

  • Namespaces, extension methods, and unsafe blocks

  • Type aliases


Variables & Constants

Use var for mutable bindings and const for immutable:

var first = 0       // mutable
const second = 1    // immutable

Optionally, annotate types with : Type:

var count: int = 42
const name: *char = "Chemical"

Built‑In Types

Chemical provides a range of primitive types:

  • Boolean & Characters: bool, char, uchar
  • Integers: short, ushort, int, uint, long, ulong
  • Arbitrary‑Precision: bigint, ubigint
  • Floating Point: float, double
  • Function Type: (a : int, b : int) => int

Pointers and reference types also exist

  • Pointer Types: *int, *mut int
  • Reference Types: &int, &mut int

These types form the foundation for more complex data structures and interop with C via cstd.


Functions

Functions in chemical start with func keyword, Here's a function that computes sum of two integers

func sum(a : int, b : int) : int {
    return 10;
}

Extension methods would be discussed below after structs

Lets now see a generic function

func <T> print(a : T, b : T) : T {
    return a + b;
}

Calling function pointers

func call_it(lambda : () => int) : int {
    return lambda()
}

Comments

Chemical supports both single line and multiline comments

a single line comment starts with two forward slashes

// Here's my single line comment

multi line comments start with /* and end with */

/* 
    Here's my multi line comment
*/

Multi line Comments cannot be nested


Control Flow

Chemical supports a rich set of control constructs:

  • if / else

    if (condition) {
        // then‑branch
    } else {
        // else‑branch
    }
    
  • loop (infinite)

    loop {
        // runs until `break`
    }
    
  • for

    for (var i = 0; i < 10; i++) {
        printf("Iteration %d\n", i)
    }
    
  • while

    while (someCondition) {
        // ...
    }
    
  • do while

    do {
        // ...
    } while (someCondition)
    
  • switch

    switch (thing) {
        1        => { /* … */ }
        2        => { /* … */ }
        3, 4, 5  => { /* … */ }
        default  => { /* … */ }
    }
    

Null Value

In C++ there's nullptr keyword which allows you to quickly check a pointer if it's null, similarly we have null keyword

if(pointer == null) {
    // the pointer is null here
}

Enums

Enumerations (enums) are declared with the enum keyword and are fully scoped:

enum Fruits {
    Mango,
    Banana,
}

Access them by qualifying with the enum name:

let f = Fruits.Mango   // ✅
let g = Mango          // ❌ invalid: must write `Fruits.Mango`

Arrays

Array can hold multiple values and provide indexed access, Just use [] to create an array


var arr = [ first_value, second_value ]
var first_value = &arr[0] // pointer to the first value


Structs

Structs hold grouped data and methods. Use public to make them visible across modules:

public struct Point {
    var x: int
    var y: int

    func sum(&self): int {
        return x + y
    }
}

Lets create an object of this struct and call sum on it

var point = Point { x : 10, y : 20 }
var sum = point.sum()

You can omit the type when it can be inferred

func create_point() : Point {
    return { x : 10, y : 20 }
}

Constructors and Destructors

Chemical provides a way to write constructors and destructors for a struct, here the function that has annotation @make is a constructor and function with annotation @delete is a destructor

struct HeapData {

    var data : *void

    @make
    func make() {
        data = malloc(sizoef(Data))
    }

    @delete
    func delete(&self) {
        free(data)
    }

}

Inheritance

You can use inheritance to build struct definitions

struct Animal {}

struct Dog : Animal {}

struct Fish : Animal {}

You can inherit a single struct, can implement multiple interfaces

Extension Methods

Add methods after the struct definition:

func (p: &Point) div(): int {
    return p.x / p.y
}

Extension methods only support reference types that point to a container (struct / variant / static interface)


Interfaces

Define an interface of method signatures:

interface Printer {
    func print(&self, a: int)
}

Implement it in two ways:

Inline

struct ImplPrinter : Printer {
    @override
    func print(&self, a: int) {
        printf("Printed: %d", a)
    }
}

impl Block

impl Printer for ImplPrinter {
    func print(&self, a: int) {
        printf("Printed: %d", a)
    }
}

Static Interfaces

interfaces can be made static using @static annotation above them, This means interfaces will be implemented once

@static
interface Organizer {
    func organize(&self)
}

Extension methods are only possible on static interfaces, Normal interfaces cannot support extension methods


Namespaces

Similar to c++ namespaces

public namespace mine {
    
    public var global_variable : int = 0

    public struct Point {
        var x : int
        var y : int
    }

}

Access members like this

func temp() {
    var p = mine::Point { x: 10, y: 10 }
}

Using statement

You can use the using keyword to bring symbols for a namespace into current scope

using namespace std;

or just a single symbol

using std::string_view

Variants & Pattern‑Matching

Variants are tagged unions:

variant Optional {
    Some(value: int),
    None(),
}

Create and return them:

func create_optional(condition: bool): Optional {
    if (condition) {
        return Optional.Some(10)
    } else {
        return Optional.None()
    }
}

Match on them with switch (no case keyword):

func check_optional(opt: Optional) {
    switch (opt) {
        Some(value) => { printf("%d", value) }
        None        => { /* nothing */ }
    }
}

You can easily check a variant using is keyword

func is_this_some(opt: Optional): bool {
    return opt is Optional.Some
}

Members can be extracted easily and safely using this syntax

func get_value() : int {
    // default value is -1 if its not `Some`
    var Some(value) = opt else -1
    printf("the value is : %d\n", value);
}

It supports different else cases

func print_value() {
    // return early without printing if its not `Some`
    var Some(value) = opt else return;
    printf("the value is : %d\n", value);
}

func get_value() : int {
    // compiler assumes its always `Some`
    var Some(value) = opt else unreachable;
    printf("the value is : %d\n", value);
}

Unsafe Blocks

By default, Chemical enforces safety checks. To perform unchecked or low‑level operations, wrap code in unsafe:

unsafe {
    var value = *ptr    // raw pointer dereference
}

The compiler will emit an error if you attempt pointer dereference or other unsafe ops outside of an unsafe block.


Type statements (typealias)

Type alias allows us to alias a type, Lets see

type MyInt = int

Now you can use MyInt instead of int

func check_my_int(i : MyInt) : bool