In modern times, there are many strategies for managing memory such as reference counting, garbage collection, RAII, and of course manual memory management. However, with many gigabytes of RAM now an established standard in new systems, why bother worrying about memory at all?
Leek uses a bleeding edge and blazingly fast memory management strategy called "exiting". Memory is allocated as needed and avoids slow de-allocation calls by not doing them. Your operating system is more than capable of freeing the used memory when your program exits, so why bother incurring wasteful runtime cost?
Leek enables you to move fast and run away from your problems. Even if you manage to use up all of the available system memory, modern operating systems have sophisticated swap file implementations. This allows you to use disk space as RAM when there is no physical memory left.
Modern serverices and applications don't keep a persistent server running. Thats old school! Now, serverless edge functions are dominating the industry with low deployment costs and automatic scaling.
Leek's memory management ideology aligns very well with the edge computing model. Leek starts fast and doesn't worry about deallocating memory since the instance will only live for a very short period of time. This makes Leek a great choice for your next serverless edge application (once an HTTP package is implemented).
Leek uses a Rust inspired syntax, but differs slightly. Semicolons are not necessary anywhere, and commas are not necessary in many places either.
All binary programs require a main
function. To print to the standard output, use the built in global println
function.
fn main() {
println("Hello, world!")
}
In Leek, allocating variables on the stack violates the principle of memory management through exiting. Thats why, all local variables get allocated on the heap. Declare a variable with the leak
keyword like so:
fn main() {
leak a = 0
// Prints "0"
println("{}", a)
a = 1
// Prints "1"
println("{}", a)
}
Arguments to functions can be defined with the comma separated <identifier>: <type>
syntax, and return types can be declared using an arrow (->
).
To return a value from a function, use the yeet
keyword.
fn add(a: i32, b: i32) -> i32 {
yeet a + b
}
fn main() {
// Prints "3"
println("{}", add(1, 2))
}
Declare constants with the perm
keyword. A strict type definition is required. Constant variables will not leak any memory at runtime, but can not be mutated.
perm PI: f64 = 3.141592653589793
fn main() {
// Prints "3.141592653589793"
println("{}", PI)
}
Declare static variables with the hold
keyword. A strict type definition is required. Static variables will be lazily allocated at runtime, and can be mutated at any point in the program.
hold NUM: i32 = 0
fn mutate() {
NUM += 1
}
fn main() {
// Prints "0"
println("{}", NUM)
mutate()
// Prints "1"
println("{}", NUM)
mutate()
// Prints "2"
println("{}", NUM)
}
Define structs with the struct
keyword, and declare fields with their name and type (no commas required!). Create a struct with the name and its members inside brackets. Access its fields with dot notation.
struct Person {
name: String
age: i32
}
fn main() {
leak alice = Person {
name: "Alice"
age: 18
}
// Prints "Alice is 18 years old."
println("{} is {} year old.", alice.name, alice.age)
}
Leek does not support object oriented programming, but functions can be scoped to a struct and accessed with dot notation in a similar way to many OOP style languages. This is syntactic sugar for passing in the struct as the first argument to a function.
struct Person {
first_name: String
last_name: String
}
fn Person::full_name(this) -> String {
yeet format("{} {}", this.first_name, this.last_name)
}
fn main() {
leak root = Person {
first_name: "John"
last_name: "Smith"
}
println("{}", root.full_name())
}