Syntax

type Vector3
    def with_y self (y : f32) = Vector3 self.x y self.z

The self parameter prevents the y field from being shadowed by the y parameter.

let enabled_extension_names = ["VK_EXT_debug_report"
                               "VK_EXT_debug_utils"
                               "VK_KHR_surface"
                               "VK_KHR_xcb_surface"
                               "VK_KHR_xlib_surface"]

Commas are not required if each array element is located on a separate line or lines.

let thickness = (left = border.left
                 right = border.right
                 up = border.up
                 down = border.down)

let size = Atom<(u32, u32) width height> (0, 0)

Tuple fields can be named on creation, or when a tuple type is specified. Names have no impact on compatibility.

val identity = Matrix3 1
                       m22 = 1
                       m33 = 1                    
                       f@ struct@zero

Field values can be set positionally, by name or with a filler. Applies to object creation, initialization of a structure, type inheritance and function invocation. Type of a filler must either match the type of the entity being created, or be a tuple with named fields.

text
|> lines
|> filter { line -> line.starts_with "layout" }
|> map { remove_comment _ }

Closures are enclosed in curly braces. Each use of underscore returns the next parameter.

filter and map are methods of the List type.

object Obs =
    def map<T, U> (list : List<T>) (f : T -> U) : List<U> = ...

let squares = numbers |> Obs.map { x -> x * x }        

numbers is passed to Obs.map as the first argument.

type Array<T> @byval =
    val size : u32
    let ptr @param = kedr/alloc<T> size

The @param attribute allows a replacement value to be passed as a named argument, can be used in functions as well.

let up_right = Vector3 left.as<f32> 0 border_z
let adjusted_size = size as f32 * 1.5 |> as<u32>

Type cast can be written without parentheses.

import num/vector_f32/Vector3
                      Vector4
           vector_i32/Vector2i

control.set_width width
        set_height control.measure_height
        arrange

Methods set_width, set_height and arrange are called on the same control binding.

type CString ptr
    fun get (i : u32) = ptr[i]

The only item of a tuple is bound to the ptr.

Special functions are defined with fun, fun get is an indexer getter.

type Slice<T> @byval =
    val ptr : Ptr<T>
    val size : u32

type MutSlice<T> @byval @[mut_of Slice] =
    val ptr : MutPtr<T> @impl

    inherit Slice<T>

The ptr field has different types for Slice and mut Slice.

type Object =
    var room : Room @late

The room binding is not a constructor parameter, will throw an error if accessed before assigned.

# Single-line comment

/* Multiline comment */

Closing part of a multiline lexeme is optional.

Memory management

let vector @owner = Vector3@ref 1 3 8

Structure is initialized on the heap if @ref suffix is added to the type name. Binding vector is of type mut ref Vector3, which can also be written as MutRef<Vector3>. References of this kind in essence are pointers without arithmetics.

The @owner attribute frees memory before binding goes out of scope, @[owner function] — before containing function returns.

type App =
    val name : String

let app = App "Editor"

Automatic reference counting is applied to objects by default.

let app = App@mrc "Editor"

kd/retain app
kd/release app

The @mrc modifier switches object to manual reference counting, which is conducted through the kd/retain and kd/release functions.

let app = App@ref "Editor"

kd/free app

Here app refers to an object on the heap. Must be freed manually with the kd/free function.

let app = App@mem "Editor"
let app_ref = app
let app_copy = app@copy

The app binding of type mem App contains object's memory. Accessing app returns a reference of type App. Copying requires the @copy modifier.

type App @mem =
    val name : String

The default option can be selected using an attribute.

Visibility and mutability

val defines a binding, var — mutable binding, def — a function, let — binding or function, private to a file, local — binding or function, private to a module.

var align_h @mut = AlignH/Stretch
val items @mut = List<Control>.new

The List type has a mutable version mut List. Readonly type cannot be casted back to mutable.

By default bindings become readonly when either the file or module ends, which is equivalent to the @[mut private] attribute. The local and internal scopes are also available.

type Grid @mut =
    var count : u32 = 0
    var distance : u32 = 0

Fields become mutable everywhere because of the @mut attribute at the type level.

internal@

var array = Array<T> 0

Apart from the let and local keywords, visibility is also restricted using directives: private@ — private in file, local@ — private in module, internal@ — private in crate.

Class

class Compare =
    def compare (other : Self) : Ordering

    def (>) (rhs : Self) =
        let result = compare rhs
        result == Ordering/Greater

    ...

type TextPos = struct
    line : u32
    char : u32

    def compare (other : TextPos) = when
        line < other.line -> Ordering/Less
        line > other.line -> Ordering/Greater
        char < other.char -> Ordering/Less
        char > other.char -> Ordering/Greater
        else -> Ordering/Equal

    is Compare

Type can be declared as belonging to a class if it corresponds to all of the class's requirements.

Mixin

type Control @abstract =
    def measure (w : u32) (h : u32)
    def arrange

mixin SingleChildLayout =
    require Control

    def Control.measure w h =
        measure_single_child self w h

    def Control.arrange =
        arrange_single_child self

type Button =
    inherit Control
    include SingleChildLayout

Control declares abstract methods measure and arrange. The SingleChildLayout mixin can only be included in a type that inherits Control. Button obtains all members of SingleChildLayout.

Generic declaration

object Kd =
    def hash<T> @decl (x : T) (state : HashState)

def Kd.hash @impl (x : bool) state =
    let i = if x then 1 else 0
    Kd.hash<i32> i state

Specializations of the Kd.hash function are defined separately for each combination of argument types.

Attached functions

type Control =
    var width : u32 = 0
    var min_width : u32 = 0
    var max_width = u32.max

    coerce width { _.clamp min_width max_width }

The value of width will always be between min_width and max_width.

observe width { _ w ->
    let event = SizeEvent/Width w
    push event }

The closure is invoked after each write to the field.

Dependency injection

type Selector =
    let overlay : Overlay @auto

let overlay @publish = display.overlay

let selector = Selector.new

Bindings with the @auto attribute receive values from published bindings if both name and type match.

Object tree

let stack = Stack
    align_h = AlignH/Left
    items <- margin, text_block
    run@ set_fixed_width 200

Expression creates a new Stack object, assigns AlignH/Left to the align_h field, adds margin and text_block to the items list, invokes the set_fixed_width method.

stack
    align_v = AlignV/Center
    is_horizontal = true

The type name is replaced with the binding name, so a stack is returned instead of a new object.

let border = Border.new
let stack = Stack.new

border
    stack
        Button
            text = "save"
            on_press <- { save_current_file }
        Button
            text = "load"
            on_press <- { show_load_dialog }

stack is assigned to border.content and buttons are added to stack.items. The content and items fields have the @dst attribute.