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