Interfaces
Promise that several classes share the same methods and fields, then pass any of them wherever the interface is the type.
An interface lists method signatures and fields with no code. A class that implements it is checked against every member by shot check, and code typed with the interface accepts any class that fits.
Declaring one
An interface is a file of its own, in the folder of the system it belongs to.
Wallet/Payer.shot
types script.Parent.Types
rootdoc {
What a wallet and a vault have in common: checking, paying and a name to show.
}
interface Payer = {
doc {True when it holds at least amount coins}
CanPay(amount : number) : boolean
doc {The actor takes amount coins from it; false and why when it can't}
Pay(actor : number, amount : number) : (boolean, string?)
doc {Display name}
Label : string
}- Members are method signatures, Name(params) : Return with no body, and fields, Name : Type. All are public.
- No generics, constructors or statics.
- It compiles to an exported type in the system's Types module and to no module at all: there is nothing to require. Every file of the folder sees the type; another folder imports it in its Types.shot (import Payer from @shot.Wallet).
- It can't be its folder's entry file (Wallet/Wallet.shot), since that file is the folder's module.
Implementing it
server class Vault implements Payer = { ... }
class PiggyBank extends Wallet implements Payer, Priced = { ... }- implements comes after extends and takes one or more interfaces.
- The class, or a class it extends, must have every member: each signature as a public method (not static) whose types fit, each field as a field.
- No override: implementing a member is not overriding one.
What shot check reports
The messages shot check gives for interfaces:
Wallet/Vault.shot:3:20 Vault implements Payer but has no Worth() : number
Wallet/Wallet.shot:3:14 Wallet implements Payer, but a member doesn't fit it: Property 'Pay' is not
compatible. Expected this to be exactly '(any, number, number) -> (boolean, string?)' but got
'(Wallet, number, string) -> (boolean, string?)' caused by: Argument #3 type is not compatible. ...
implements Priced: no interface called Priced (shot find Priced)
implements Priced: Priced is not visible here; import it in this folder's Types.shot: import Priced from @shot.Market
Chest implements Priced but its PriceFor is internal: what an interface promises is public
use Payer: an interface is only a type, with nothing to require. ...The fit is checked by Luau's type checker: each class is converted to the interface's type once, in its Types module. So a member that fits in Luau terms (a wider parameter, a narrower return) is accepted.
Using it
- As a type, anywhere the folder sees it: function ChargeAll(payers : {Payer}, actor : number, amount : number) calls payer:Pay(actor, amount), checked against the interface. A Wallet or a Vault can be passed for it.
- shot implements Payer: its members and every class that implements it, and subclasses through them.
- shot refs Payer.Pay: every call made through a value typed Payer. Calls on a Wallet are Wallet.Pay's (shot refs Wallet.Pay).
- shot trace Payer.Pay: the interface member, then each class's version and what it does.
- shot rename refuses an interface member: rename it and each class's member by hand (shot implements lists them).
