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. Type of a filler must either match the type of the entity being created, or be a tuple with named fields. Works for object creation, initialization of a structure, type inheritance and function invocation.

let vector = 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.

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.

let list @owner = List@mrc.new

Modifier @mrc stands for manual reference counting. The @owner attribute guarantees that memory is freed before the containing function returns, is also available for object fields.

The new keyword is used only for types without constructor parameters.

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 Entry =
    path : String
    created : DateTime

    | File size : u32
    | Directory entries : Slice<Entry>
                | Local
                | Remote url : String

Entry and Directory are sum types. Structures File, Local and Remote inherit the path and created fields. Local and Remote also contain the entries.

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.

Visibility and mutability

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

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.

When the file ends, var bindings become readonly and val bindings of mutable types get readonly version of the type. The @mut attribute serves to prevent this.

var size : u32 @[mut internal] = 0

The @mut attribute argument specifies the mutability scope.

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

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

begin@ editor

type Editor =
    var count : u64 = 0
    local mut should_separate = false
    let rectangle = Rectangle.new

end@ editor

editor is a logical file. Outside of editor the count binding becomes readonly, while should_separate is no longer visible. rectangle becomes inaccessible when either editor or the physical file ends.

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 logical file, protected@ — private in hierarchy, internal@ — private in crate.

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 add_popup : Control -> Unit @auto
    let remove_popup : Control -> Unit @auto

let main () =
    let selector = Selector.new

let add_popup @publish = app.display.add_popup
let remove_popup @publish = app.display.remove_popup    

main

Values of the published add_popup and remove_popup bindings will be passed to the corresponding fields of the Selector object. Both name and type need to 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
    thickness = 5
    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.