Система типов

Программист может объявить типы следующих видов:

  • объект
  • структура
  • объединение
  • класс
  • именованный кортеж
  • символ
  • тип-сумма
  • флаги

Объект

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

У типа Buffer пять полей, каждое из которых также является параметром конструктора.

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

Во время наследования мы передали значения полей type и offset, оставшиеся три поля становятся параметрами конструктора StorageBuffer. К ним добавляются еще два параметра/поля device и memory.

Видимость let привязок и функций ограничена текущим файлом.

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

Равенство объектов с атрибутом data определяется содержимым полей.

import collection/List@mrc

let list @owner = List.new

Модификатор @mrc, расшифровывается как manual reference counting, даёт доступ к версии типа без автоматического подсчета ссылок. Атрибут @owner гарантирует освобождение памяти перед выходом из содержащей привязку функции, также доступен для полей объектов.

Ключевое слово new используется для типов без параметров конструктора.

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

У типа List есть изменяемая версия mut List. Тип только для чтения нельзя снова преобразовать в изменяемый.

Без атрибута @mut по окончании файла привязка align_h превратится в только для чтения, а items получит тип List<Control> вместо mut List<Control>.

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

Объекты передаются по значению, если задан атрибут @byval.

Поддерживается множественное наследование, но каждый тип может быть унаследован только один раз.

Структура

type ClearDepthStencilValue = struct
    depth : f32
    stencil : u32

Может наследовать другие структуры.

Объединение

type ClearValue = union
    color : ClearColorValue
    depth_stencil : ClearDepthStencilValue

Все поля указывают на один и тот же адрес в памяти. При инициализации нужно задать значение одного поля.

Класс

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 CString = ptr CChar

Чаще всего имеет только один элемент.

Символ

Также известен как единичный тип. По сути, является именованным кортежем с нулём элементов.

type None = symbol

Используется в типах-суммах.

Тип-сумма

Отличается от объединения наличием информации об активном поле.

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

Перечисление это тип-сумма единичных типов.

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

Target/Buffer это именованный кортеж, Target/Image — структура.

type Option<T> =
    | None
    | Some T

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

Option позволяет представить отсутствие значения. Функция возвращает Result, чтобы передать информацию об ошибке в случае неудачи.

type Metal @open = enum
    Iron | Copper | Nickel

type Metal
    Silver | Gold

type Platinum = symbol
    inherit Metal

К открытым типам-суммам поля можно добавлять в любой точке кода. Модификатор enum ограничивает типы полей единичными.

Флаги

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

let queue_flags = QueueFlags/Graphics | QueueFlags/Transfer

assert queue_flags.contains QueueFlags/Graphics