Flux is a compiled systems language that combines C-like performance with Python-inspired syntax. It's for everyone, designed to have all the bells and whistles you could want in one place. Gone now are the days of writing your performance critical code in one language and calling it from another.
Characteristics:
#import "standard.fx";
#ifdef __WINDOWS__
def some_win_generic() -> LPCSTR*;
#else
#ifdef __LINUX__
def some_nix_generic() -> void*;
#endif;
#endif;
Macro definitions must have a value, 0 included. Example:
// Defined:
#def MY_MACRO 1; // Considered defined.
#def NOT_DEFINED 0; // Considered undefined.
#ifdef NOT_DEFINED // False
#ifndef MY_MACRO // False
Define types with exact bit widths and alignment:
unsigned data{1} as bit; // 1-bit type
unsigned data{13:16} as custom; // 13 bits, 16-bit aligned
unsigned data{32} as u32; // Standard 32-bit unsigned
Extract individual bits from bytes as named fields:
struct Flags {
unsigned data{1} enabled;
unsigned data{1} error;
unsigned data{1} ready;
unsigned data{1} busy;
unsigned data{4} mode;
};
byte status = 0b10110001;
Flags f from status;
if (f.enabled & !f.error) { /* ... */ };
Functions:
def add(int x, int y) -> int {
return x + y;
};
Function Prototypes:
// Single def, multiple signatures.
def foo() -> void,
foo() -> int, // Can declare multiple signatures on one line.
foo() -> float; // Identical names are recommended.
def abc() -> void,
jki() -> void, // Even with different names!
xyz() -> void; // Different names are not recommended.
Universal External FFI:
Flux has an operator called the "no mangle" operator, !!, which instructs the compiler to not mangle the function name to its right. This only applies to function names.
extern def stcmp(byte*,byte*)->int; // Single-line
extern // Multi-line
{
def foo() -> void;
def zad() -> void;
};
// !! cascades when performing multi-signature def
extern
{
def !!
foo() -> void,
bar() -> void,
baz() -> void; // All safe from name mangling
};
Objects (OOP):
object Vector3 {
float x, y, z;
def __init(float x, float y, float z) -> this {
this.x = x; this.y = y; this.z = z;
return this;
};
def __exit() -> void {}; // Explicit returns for void functions unnecessary.
def length() -> float {
return sqrt(this.x^2 + this.y^2 + this.z^2);
};
};
Structs (Data-only):
struct Point {
float x, y, z;
};
Memory Management:
int* ptr; // Allocate
*ptr = 42;
(void)ptr; // Deallocate explicitly
Skip declaring a variable:
int* px = @55; // Allocate 55 and get its address.
Round trip (pointer, to int, and back):
int x = 5;
int* px = @x;
int pxk = px; // Address as integer
int* py = (@)pxk; // Address as pointer
This can segfault or crash if your default pointer width is 64 bits.
The safe way to do this round trip with 64 bit pointers is this:
int x = 5;
int* px = @x;
u64 pxk = px; // Address as integer, pxk is big enough to hold a 64 bit pointer
int* py = (@)pxk; // Address as pointer, pointer will be 64 bits and can accept pxk
Flux treats all data the same. It's all just numbers.
Ownership (Optional):
def foo(~int c) -> void
{
// do something with c
};
def make() -> int {
~int x = 42; // Mark with "tie" operator ~ (tied int)
foo(~x); // Untie from main, tie to foo
print(x); // Compile-time Use-After-Untie error.
return 0;
};
Locality:
Locals cannot be passed to a function or returned from a function.
#import "standard.fx";
def foo(int z) -> int
{
return z;
};
def main() -> int
{
local int y = 5;
foo(y); // Illegal, compile error
return 0;
};
Endianness is part of the type
Network protocols use big-endian. Every other language makes you manually convert with htons(), ntohs(), htonl(), ntohl().
In Flux, endianness is part of the type:
unsigned data{16::1} as big_endian; // ::1 = big-endian
unsigned data{16::0} as little_endian; // ::0 = little-endian
big_endian network_value = 0x1234;
little_endian host_value = network_value; // Automatic byte swap
Cross an endianness boundary, get automatic conversion. Stay within the same endianness, no conversion. The type system knows, so you don't have to manage it manually.
Build complex bit patterns by listing values.
Need to pack several values into a single integer? Most languages make you calculate bit positions and shifts:
(a << 24) | (b << 16) | (c << 8) | d
Flux lets you list the values in order:
unsigned data{4} version = 4;
unsigned data{4} ihl = 5;
unsigned data{8} tos = 0;
unsigned data{16} length = 60;
unsigned data{32} packed = [version, ihl, tos, length];
The compiler knows each field's bit width, so it knows how to pack them. You don't calculate positions - you just list what you want, in order.
This is compositional bit manipulation. Instead of doing arithmetic on bits, you compose values and let the type system handle the packing.
You can still do it the old way and manually move bits around if you like.
Flux follows a "high-trust" model:
This means:
Flux is well-suited for:
Flux may not be the best choice for:
Flux is in active development. The language specification is complete, but implementation is ongoing.
What exists:
What's being built:
#import "standard.fx";
struct Packet
{
unsigned data{8} type;
unsigned data{16} length;
unsigned data{32} timestamp;
};
def main() -> int
{
byte[7] bytes = [0x01, 0x00, 0x20, 0x5F, 0x12, 0x34, 0x56];
Packet pkt = Packet from bytes;
print("Type: \0");
print(pkt.type); print();
print("Length: \0");
print(pkt.length); print();
print("Time: \0");
print(pkt.timestamp); print();
return 0;
};
Note: Flux is a systems programming language that assumes you understand memory management and low-level programming concepts. If you're new to systems programming, work through the tutorial documentation carefully.
Flux is actively developed and approaching self-hosting. We're building the future of systems programming.
Current Status: 100% of reduced specification complete, working compiler, real programs running.
Bug fixing and refactoring are currently the names of the games. There are still some small issues here and there, as well as minor missing functionality. More features may end up being added before the bootstrap.
Copyright (C) 2024 Karac Von Thweatt. All rights reserved.