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.