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