lloyAlloy on GitHub
requires
Docs

requires

Updated
attribute service on impl as
    requires public function Start(self)
    requires private field state: number
    requires function Stop(self): boolean
end

One clause of an attribute contract: what the thing the attribute sits on must carry. The compiler checks it where the attribute is used and emits nothing, because a contract is a check.

A clause reads requires <visibility>? <kind> <name> <shape>. The visibility is public, private, or absent, and absent takes either. The kind is function or field. The shape is a parameter list for a function, with a return type when the clause writes one, and : T for a field. A clause with no shape asks for the member alone. A function shape compares the count of parameters and the type of each. The name of a parameter is no part of its type, so _y meets y.

The targets that carry members take a clause: struct, impl, namespace, enum, interface, trait. A clause on any other target reports at the declaration. A struct and its impl blocks are one type, so a clause on either reads both: requires field in an on impl contract asks the struct for the field, and requires function in an on struct contract asks its impls for the method.

each writes one clause per entry of a list argument; alloy doc each has it.

The check is structural. A type that happens to declare Start meets the clause without meaning to, the way an interface works. A trait is the nominal one: impl Trait for Name says so out loud.

A clause fixes the name of the member it asks for, so naming_convention does not report that name. Init stays Init under a preset that writes methods in snake_case.

The word is free as a name. requires opens a clause only inside an attribute ... as ... end body, so local requires = 1 and requires(f) read the Luau way.