Classes
A class is one block: fields, constructor and methods side by side. The metatable, the self parameters and the types are written for you.
You'll learn fields, public and internal, constructors and init(), methods and self, statics.
A class
Wallet, one player's coins, both ways. It goes in Wallet/Wallet.shot, named like its folder, so it is the system's entry point: require(@shot.Wallet) returns it.
--!strictlocal Types = require(script.Parent.Types)local Coins = require(script.Parent.Coins)local Wallet = {}Wallet.__index = Wallettype Fields = { Balance: number, _history: {Types.Entry},}export type Wallet = typeof( setmetatable({} :: Fields, Wallet))function Wallet.new(balance: number): Wallet return setmetatable({ Balance = balance, _history = {}, }, Wallet)endfunction Wallet.Add(self: Wallet, amount: number, reason: Types.Reason) self.Balance += amount table.insert(self._history, { Amount = amount, Reason = reason })endfunction Wallet.Describe(self: Wallet): string return Coins.Format(self.Balance)endreturn Wallet
types script.Parent.Typesuse Coinsclass Wallet = { public Balance : number internal _history : {Entry} constructor new(balance : number) local self : Wallet = init() self.Balance = balance self._history = {} return self end public Add(amount : number, reason : Reason) self.Balance += amount table.insert(self._history, { Amount = amount, Reason = reason, }) end public Describe() : string return Coins.Format(self.Balance) end}
What it compiles toWallet/Wallet.luau
--!strict local Types = require(script.Parent.Types) export type Reason = Types.Reason export type Entry = Types.Entry export type Wallet = Types.Wallet type WalletClass = Types.WalletClass export type Coins = Types.Coins local Coins = require(script.Parent.Coins) local Wallet = {} Wallet.__index = Wallet --@public Balance number --@internal _history {Entry} --[[$constructor]] function Wallet.new(balance : number) : Wallet local self : Wallet = setmetatable({},Wallet) :: any self.Balance = balance self._history = {} return self end --[[$public]] function Wallet.Add(self : Wallet, amount : number, reason : Reason) self.Balance += amount table.insert(self._history, { Amount = amount, Reason = reason, }) end --[[$public]] function Wallet.Describe(self : Wallet) : string return Coins.Format(self.Balance) end return Wallet
Tip use Coins needs no path here: Coins.shot is in the same folder.
The members
public Balanceanyone may use;internal _historyonly code in this folder. There is noprivate.- Every member starts with its word:
public,internal,constructororoverride. A bareDescribe() : stringis an error. constructor new(...)makes an object, called with a dot:Wallet.new(10). Any name, as many as you need, no return type.init()issetmetatable({}, Wallet) :: any. Writelocal self : Wallet = init(), set every field with no default, returnself.- A method has no
selfparameter; inside itselfis the object. Call it with a colon:wallet:Add(15, "Pickup"). public static Empty() : Walletbelongs to the class:Wallet.Empty().public Limit : number = 1000is a class property: the default each object reads until it sets its own.
The types it writes
The object's type (fields, then methods) and WalletClass, the class table's type:
--[[$public]] export type Wallet = { Balance : number, _history : {Entry}, Add : (self : Wallet, amount : number, reason : Reason) -> (), Describe : (self : Wallet) -> string, } --[[$internal]] export type WalletClass = { new : (balance : number) -> Wallet, Add : (self : Wallet, amount : number, reason : Reason) -> (), Describe : (self : Wallet) -> string, }
Using it
@server enabled use @shot.Wallet local wallet = Wallet.new(10) wallet:Add(15, "Pickup") print(wallet:Describe())
==== Hello [server print] 25 coins [client:Ana print] client started ==== summary Hello OK (2 lines, 0 errors, 0.1s virtual) 1 of 1 scenario(s) passed
internal is a rule the checker keeps. Add print(#wallet._history) to Init/Server.shot:
./Init/Server.shot:8:15 internal Wallet._history is used outside Wallet 1 errors in 1 file (5 files checked, 2.5 s)
Add public static Empty() : Wallet that returns Wallet.new(0) and call Wallet.Empty() from Init/Server.shot. Then call it on an object, wallet.Empty(): shot check answers Key 'Empty' not found in table 'Wallet', because statics belong to the class.
