lloyAlloy on GitHub
Strict by default
Docs

Strict by default

Updated

Every .aly file checks in Luau strict mode unless the project says otherwise. alloy init writes one Luau configuration with languageMode = "strict", and the language server gives a workspace with neither file the same setting. A --!nonstrict or --!nocheck line at the top of a file still wins for that file.

On top of the checker, the compiler holds these at compile time:

match every variant has an arm, or a `default` (`alloy doc exhaustive`) new Name { } every field without a default is set; no unknown field impl T for S every method of the trait, with the trait's arity @sealed no write to an undeclared field, at runtime and at check time a->b a=>b the receiver is an `Instance`; the child is not a function remote no function, thread, Future, or Signal in a parameter (`alloy doc wire`)

alloy lint adds the nil discipline and, under [lint] strict = true, which is on unless the project turns it off, the no-implicit-any rules (alloy doc lints).

Exhaustive match

A match with no default covers every variant. The error names the one with no arm.

match msg with
    case Join(p) then greet(p)
    case Chat(p, t) then say(p, t)
end
-- `Msg` has no arm for `Leave`; add it or a `default` arm

Struct construction

The fields form sets every field without a default and names no field the struct lacks.

struct P
    x: number
    y: number = 0
end
local a = new P { y = 1 }
-- `new P { ... }` leaves `x` unset

Trait contract

An impl writes every method the trait declares without a body, with the trait's arity.

trait Shape
    function area(self): number
end
impl Shape for Sq
end
-- `impl Shape for Sq` does not write `area`

Sealed structs

A struct is open: a typo in a field name makes a new key in silence. @sealed makes it an error, at runtime and at check time. A `read` field is the one that cannot be written.

@sealed
struct Config
    volume: number
end
local c = new Config { volume = 1 }
c.volume = 2  -- fine: declared
c.volme = 2   -- error: Config has no field volme

Wire types

A remote carries data. A function, a thread, a Future, or a Signal in a parameter is an error.

remote Ping(cb: () -> ()) from client
-- parameter `cb` has type `() -> ()`, which is a
-- function type; a remote carries only data