Flix, an open-source programming language inspired by many programming languages, enables developers to write code in a functional, imperative or logic style. Flix looks like Scala, uses a type system based on Hindley-Milner and a concurrency model inspired by Go. The JVM language supports unique features such as the polymorphic effect system and Datalog constraints.
The community develops the language based on a set of principles such as: no null value, private by default, no reflection, separation of pure and impure code, correctness over performance and no global state.
main function is considered impure as the
println function has a side effect. The Flix compiler keeps track of the purity of each expression and guarantees that a pure expression doesn’t have side effects.
def main(_args: Array[String]): Int32 & Impure = println("Hello world!"); 0 // exit code
The Flix language supports Polymorphic Effects making it possible to distinguish between pure functional programs and programs with side effects. Functions are pure by default, or can explicitly be marked as pure:
def add(x: Int32, y: Int32): Int32 & Pure = x + y;
Functions with side effects can be marked explicitly as impure:
def main(_args: Array[String]): Int32 & Impure = println(add(21, 21)); 0 // exit code
The compiler displays an error
Impure function declared as pure whenever side effects are used in an explicitly marked Pure function:
def add(x: Int32, y: Int32): Int32 & Pure = x + y; println("Hello")
The separation of pure and impure code allows developers to reason about pure functions as if they are mathematical functions without side effects.
Datalog, a declarative logic programming language, may be seen as a query language such as SQL, but more advanced. Flix supports Datalog as a first-class citizen making it possible to use Datalog constraints as function arguments, returned from functions and stored in data structures. Flix may be used with Datalog to express fixpoint problems such as determining the ancestors:
def getParents(): # r = # ParentOf("Mother", "GrandMother"). ParentOf("Granddaughter", "Mother"). ParentOf("Grandson", "Mother"). def withAncestors(): # ParentOf(String, String), AncestorOf(String, String) = # AncestorOf(x, y) :- ParentOf(x, y). AncestorOf(x, z) :- AncestorOf(x, y), AncestorOf(y, z). def main(_args: Array[String]): Int32 & Impure = query getParents(), withAncestors() select (x, y) from AncestorOf(x, y) |> println; 0
This displays the following results:
[(Granddaughter, GrandMother), (Granddaughter, Mother), (Grandson, GrandMother), (Grandson, Mother), (Mother, GrandMother)]
Flix provides built-in support for tuples and records as well as algebraic data types and pattern matching:
enum Shape case Circle(Int32), // circle radius case Square(Int32), // side length case Rectangle(Int32, Int32) // height and width def area(s: Shape): Int32 = match s case Circle(r) => 3 * (r * r) case Square(w) => w * w case Rectangle(h, w) => h *