Type system

Programmer can define types of the following kinds:

  • object
  • structure
  • union
  • class
  • named tuple
  • symbol
  • sum
  • flags

Object

type Buffer =
    val type : BufferType
    var object : VkBuffer
    var size : u32
    val offset : u64
    val usage : BufferUsageFlags

The Buffer type has five fields, which are also constructor parameters.

type StorageBuffer =
    inherit Buffer type = BufferType/Storage
                   offset = 0

    let device : VkDevice
    let memory : VkMemory

    def discard =
        vk/destroy_buffer device object null
        vk/free_memory device memory null

When inheriting, we passed in values for the type and offset fields, the three remaining fields become constructor parameters for StorageBuffer, joined by device and memory.

Bindings and functions with let are private to a file.

type AttachmentFormat @data =
    val format : VkFormat
    val samples : SampleCountFlags
    val usage : ImageUsageFlags

Equality and hash of objects with @data attribute are derived from fields.

import collection/List@mrc

let list @owner = List.new

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

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

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

The List type has a mutable version mut List.

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

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

Objects with @byval attribute are passed by value.

Code directly inside of a type goes into a constructor, which can span across multiple files through extensions. The @param attribute allows a replacement value to be passed as a named argument, can be used in functions as well.

Multiple inheritance is supported, but each type can be inherited only once.

Explicit type casts are final, Buffer cannot become StorageBuffer again.

Structure

type ClearDepthStencilValue = struct
    depth : f32
    stencil : u32

Can inherit other structures.

Union

type ClearValue = union
    color : ClearColorValue
    depth_stencil : ClearDepthStencilValue

All fields point to the same memory address. Value of one field needs to be provided on initialization.

Class

type Compare = class
    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.

Named tuple

type CString = Ptr<с_char>

Most of the time has only one element, as otherwise a structure might be a better choice.

Symbol

Also known as a unit type. In essence, it is a named tuple with zero elements.

type None = symbol

Is used in sum types.

Sum

Differs from union by containing information about an active field.

type BufferType =
    | Vertex
    | Index
    | Storage
    | Image
    | Uniform

Enumeration is a sum of unit types.

type Target =
    | Buffer VkBuffer
    | Image image : VkImage
            width : u32
            height : u32

Target/Buffer is a named tuple, Target/Image is a structure.

type Option<T> =
    | None
    | Some T

type Result<T, E> =
    | Ok T
    | Error E

Option allows for representing an absence of a value. Function returns Result to pass an error message in case of a failure.

type Metal @open = enum
    Iron | Copper | Nickel

type Metal
    Silver | Gold

type Platinum = symbol
    inherit Metal

Fields can be added to open sum types at any moment. Modifier enum restricts types of fields to symbols.

Flags

type QueueFlags = flags
    | Graphics
    | Compute
    | Transfer
    | SparseBinding
    | Protected

let queue_flags = QueueFlags/Graphics | QueueFlags/Transfer

assert queue_flags.contains QueueFlags/Graphics