### Initial Luau Function Definition Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Defines a basic Luau function `dealDamage` that takes a player and a numerical damage amount. This serves as the starting point for demonstrating various commenting practices. ```lua local function dealDamage(victim: Player, damage: number) -- code end dealDamage(victim, 100) ``` -------------------------------- ### Example of extending component properties directly (discouraged) Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Shows how a component might be used if it directly accepted and merged native Roblox properties with its own, a pattern later discouraged due to potential conflicts and maintenance overhead. ```lua e(Pane, { Position = UDim2.fromScale(0.5, 0.5), }) ``` -------------------------------- ### Applying early return for damage calculation in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates the use of early returns for functions where certain conditions logically prevent further execution, using a 'dealDamage' function as an example to avoid unnecessary operations. ```Luau local function dealDamage(humanoid: Humanoid, damage: number) if damage > 0 then humanoid.Health -= damage end end ``` ```Luau local function dealDamage(humanoid: Humanoid, damage: number) if damage <= 0 then return end humanoid.Health -= damage end ``` -------------------------------- ### Example of Alphabetically Sorted Luau Require Statements Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Shows the recommended approach for 'require' statements: sorted alphabetically. This method integrates seamlessly with Luau LSP's auto-require and StyLua's 'sort_requires' feature, eliminating the need for manual management and improving developer experience. ```Luau local ReplicatedStorage = game:GetService("ReplicatedStorage") local InnerComponent = require(script.InnerComponent) local MyComponent = require(ReplicatedStorage.Ui.MyComponent) local MyComponent2 = require(ReplicatedStorage.Ui.MyComponent2) local React = require(ReplicatedStorage.Packages.React) local useStuff = require(ReplicatedStorage.Ui.Hooks.useStuff) ``` -------------------------------- ### Prioritizing consumer usage over internal implementation clarity in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Discusses the principle that internal implementation complexity is acceptable if it significantly improves the usability, performance, or safety for the consumer of the code. Uses a 'slice' function example to show how a less obvious but more efficient internal implementation ('table.move') can be preferred. ```Luau local function slice(items: { T }, min: number, max: number): { T } local result = {} for index = min, max do table.insert(result, items[index]) end return result end ``` ```Luau local function slice(items: { T }, min: number, max: number): { T } -- I can never really remember which is which, and they're all numbers, but that's okay, -- because the rest of my code can just be `slice`. return table.move(items, min, max, 1, {}) end ``` -------------------------------- ### Example of Unsorted and Sectioned Luau Require Statements Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Presents a common but discouraged pattern of organizing 'require' statements with manual sections and inconsistent sorting. This approach can lead to difficulties in maintaining a consistent standard, especially in collaborative environments, and hinders tool-assisted code generation. ```Luau local ReplicatedStorage = game:GetService("ReplicatedStorage") local React = require(ReplicatedStorage.Packages.React) local MyComponent = require(ReplicatedStorage.Ui.MyComponent) local MyComponent2 = require(ReplicatedStorage.Ui.MyComponent2) local useStuff = require(ReplicatedStorage.Ui.Hooks.useStuff) local InnerComponent = require(script.InnerComponent) ``` -------------------------------- ### Understanding `nil` and Void Return Types in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Explains the critical distinction between a function returning `nil` and a function returning no values (void) in Luau. It demonstrates how this difference impacts interactions with built-in functions and provides examples for explicitly handling return types based on function semantics. ```Luau local function returnsNothing() end local function returnsNil() return nil end ``` ```Luau print(returnsNothing()) -- Prints a blank line, as `print()` would print(returnsNil()) -- Prints "nil", as `print(nil)` would ``` ```Luau local function doSomething() print("I'm a function that performs a side effect, and I have no sensible return value") print("Thus, I return nothing.") end local function getAmmo(inventory) if inventory.selectedWeapon ~= nil and inventory.selectedWeapon.type == "gun" then return inventory.selectedWeapon.ammo end -- Don't forget me! -- `getAmmo` with no gun selected returns nil to mean "there's nothing here". -- If you forget this, you are returning void. return nil end ``` -------------------------------- ### Example of Historical Comment in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates a 'historical comment' that describes a past change (`100 is too much`). Such comments are considered noise for new readers and should be avoided as they only make sense in the context of a diff. ```lua dealDamage(victim, 50) -- 100 is too much ``` -------------------------------- ### Example Luau Table for Immutability Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Defines a nested Luau table representing game items, including a sword and a health potion. This structure is used to illustrate the concept of immutable updates and the inefficiency of deep copying when only parts of the data need modification. ```lua local items = { { name = "Sword", damage = 10, durability = 40, }, { name = "Health Potion", color = { r = 255, g = 0, b = 0, }, healthToRestore = 100, }, -- etc } ``` -------------------------------- ### Verbose Historical Comment Example in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Shows another example of a verbose historical comment that provides excessive, irrelevant context about past changes. This type of comment obscures the current purpose and usage of the code. ```lua -- Used to deal damage as a number, but then we wanted to include damage types. -- Use DamageInfo instead, you can get one from a number by using `createDamageInfo`. local function dealDamage(victim: Player, damageInfo: DamageInfo) ``` -------------------------------- ### Avoid Changelogs in Luau Code Comments Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md An example of a changelog block typically found at the top of a file. This practice should be avoided as version control systems like Git provide a more robust and accessible history of changes. ```lua -- Coded by @SuperAwesomeDev -- 2023-05-01: Fixed a bug where the getCurrentDayInApril() would crash if it was May -- 2023-04-29: Added new function for getting the current day in April ``` -------------------------------- ### Using Assert for Type Narrowing in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Explains how `assert` can be used in Luau for type narrowing, particularly in scenarios where the assertion is theoretically impossible to fail but helps the type checker. It presents a `shallowEqual` function example where `assert` is used to confirm type consistency. ```lua local function shallowEqual(x: T, y: T) if typeof(x) ~= typeof(y) then return false end if typeof(x) == "table" then assert(typeof(y) == "table") -- It's impossible for this to fail end end ``` -------------------------------- ### Preventing Runtime Errors with Luau Static Typing Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md This example demonstrates how Luau's strict typing can prevent runtime errors that would otherwise require explicit assertions. The 'good' function, with its type annotation, is superior to the 'bad' function which relies on a runtime 'assert' for type checking, as the type checker will catch incorrect usage statically. ```Lua local function bad(x) assert(typeof(x) == "number", "I wanted a number!") return x + 10 end local function good(x: number) return x + 10 end ``` -------------------------------- ### Initializing Roblox Services with GetService in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates the recommended practice of using 'game:GetService("ServiceName")' at the top of a Luau file to initialize Roblox services alphabetically. This avoids issues with services not being available at script runtime or having different names, and discourages the use of 'game.ServiceName' or the global 'workspace'. ```Luau local ReplicatedStorage = game:GetService("ReplicatedStorage") local ServerScriptService = game:GetService("ServerScriptService") local Workspace = game:GetService("Workspace") ``` -------------------------------- ### Organize Luau Scripts as Implementation Details Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md When splitting the implementation of a script without altering its consumer behavior, it's recommended to place implementation details (sub-scripts) within the main script's directory. This approach helps in modularizing code while maintaining a clear logical grouping, as demonstrated by splitting a single `Toolbar.luau` file into an `init.luau` and separate component files within a `Toolbar` directory. ```Luau -- src/shared/Ui/Toolbar.luau (Original single file structure) local function ToolbarButton() -- etc end local function ToolbarRow() -- etc end local function Toolbar() -- etc end return Toolbar ``` ```Text src/shared/Ui/Toolbar (Preferred directory structure) L init.luau L ToolbarButton.luau L ToolbarRow.luau ``` -------------------------------- ### Using `Pane` component with `native` property (recommended) Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates how to use the `Pane` component when it's implemented with the `native` property, clearly separating custom properties from Roblox instance properties for cleaner component usage. ```lua return e(Pane, { native = { Position = UDim2.fromScale(0.5, 0.5), } }) ``` -------------------------------- ### StyLua Configuration for Sorting Luau Requires Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Provides the 'stylua.toml' configuration snippet necessary to enable automatic alphabetical sorting of 'require' statements using StyLua, ensuring consistency and leveraging tooling benefits. ```TOML [sort_requires] enabled = true ``` -------------------------------- ### Use Generalized Iteration in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Recommends using Luau's generalized iteration (`for i, v in t do`) as the preferred method for iterating over tables. This syntax is more concise and covers common iteration needs, reducing boilerplate code. ```Luau for i, v in t do ``` -------------------------------- ### Basic `Pane` component with default Roblox instance properties Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Defines a basic `Pane` component that wraps a Roblox `Frame` instance, applying common default properties like `BackgroundTransparency` and `BorderSizePixel` to provide a consistent base style. ```lua local function Pane(props: { children: React.ReactNode, }) return e("Frame", { -- Some nice defaults BackgroundTransparency = 1, BorderSizePixel = 0, Size = UDim2.fromScale(1, 1), }, props.children) end ``` -------------------------------- ### Implementing `Pane` component with `native` property (recommended) Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Shows the recommended implementation of the `Pane` component, where native Roblox properties are passed through a dedicated `native` table. This simplifies property handling, improves type safety, and avoids conflicts with custom component properties. ```lua local function Pane(props: { native: { [any]: any }?, children: React.ReactNode, }) return e("Frame", join({ -- Some nice defaults BackgroundTransparency = 1, BorderSizePixel = 0, Size = UDim2.fromScale(1, 1), }, props.native), props.children) end ``` -------------------------------- ### Recommended `pcall` Usage for Luau Functions Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates acceptable uses of `pcall` shorthand for regular functions and discusses when to use an anonymous function wrapper. It also cautions against unnecessary anonymous function wrappers for no-argument calls, preferring direct `pcall` calls for simplicity. ```Luau pcall(call, 1, 2, 3) ``` ```Luau pcall(function() call(1, 2, 3) end) ``` ```Luau pcall(saveMoney, player, 100) ``` ```Luau pcall(function() return saveMoney(player, 100) end) ``` ```Luau pcall(function() return f() end) ``` ```Luau pcall(f) ``` -------------------------------- ### Avoid `pcall` Shorthand for Luau Methods Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md This section advises against using `pcall`'s shorthand syntax for method calls (e.g., `pcall(part.Destroy, part)`) due to reduced readability. It demonstrates how `pcall` works and provides a more readable alternative using an anonymous function. ```Luau -- Destroy the part, but don't error if we can't pcall(part.Destroy, part) ``` ```Luau pcall(function() part:Destroy() end) ``` -------------------------------- ### Using `native` property for Roblox instance properties (recommended) Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates the recommended way to pass native Roblox instance properties to a custom component using a dedicated `native` table, separating them from custom component-specific properties for clarity and maintainability. ```lua e(Pane, { padding = 5, -- Some custom property that doesn't exist on the native Roblox class. Make it a normal property. native = { BackgroundColor3 = Color3.new(1, 1, 1), -- For everything else... } }) ``` -------------------------------- ### Prefer UDim2.fromOffset and UDim2.fromScale for UI Dimensions in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md This guideline recommends using `UDim2.fromOffset(x, y)` and `UDim2.fromScale(x, y)` over the more verbose `UDim2.new` for creating UI dimensions in Luau. This practice reduces visual noise and improves clarity, making it easier to discern the type of dimension being used at a glance. ```Luau -- Prefer these for clarity: local offsetDim = UDim2.fromOffset(100, 50) local scaleDim = UDim2.fromScale(0.5, 0.2) -- Avoid this for clarity, as it's harder to distinguish at a glance: local oldOffsetDim = UDim2.new(0, 100, 0, 50) local oldScaleDim = UDim2.new(0.5, 0, 0.2, 0) ``` -------------------------------- ### Implementing direct property extension (discouraged) Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates the implementation details for a component that directly accepts and merges native Roblox properties with its own. This approach requires manual filtering of custom properties and can lead to issues with type safety and future Roblox property additions. ```lua local function Pane(props: { children: React.ReactNode, [any]: any, }) local native = table.clone(props) -- Remove any extra fields native.children = nil return e("Frame", join({ -- Some nice defaults BackgroundTransparency = 1, BorderSizePixel = 0, Size = UDim2.fromScale(1, 1), }, props), props.children) end ``` -------------------------------- ### Ensuring Type Safety with Optional Keys in Luau Tables Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates how to correctly type Luau tables where keys might not always be present, using the `V?` syntax. It contrasts an incorrect approach that leads to runtime errors with a type-safe solution that handles potential `nil` values explicitly. ```Luau local playerPoints: { [Player]: number } = {} local function givePoints(player: Player, amount: number) -- Typed as number... local currentPoints = playerPoints[player] -- Oops! If the player had no points, this will error! currentPoints += amount end ``` ```Luau local playerPoints: { [Player]: number? } = {} -- New ^ local function givePointsBad(player: Player, amount: number) -- Typed as number?... local currentPoints = playerPoints[player] -- Type error! Can't `+=` nil currentPoints += amount end -- Let's try again... local function givePoints(player: Player, amount: number) local currentPoints = playerPoints[player] -- Handle the potential of nil.. if currentPoints == nil then playerPoints[player] = amount else playerPoints[player] += amount end end ``` -------------------------------- ### Structuring Luau libraries: Individual files vs. monolithic utilities Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Advocates for splitting large utility libraries into individual files for each function or related set of functions. This approach enhances modularity, testability, reusability, reduces dependency issues, and improves editor autocomplete features. ```Luau -- Bad -- TableUtil.luau local TableUtil = {} function TableUtil.flatten() -- etc end function TableUtil.reverse() -- etc end return TableUtil ``` ```Luau -- Good -- flatten.luau local function flatten() -- etc end return flatten -- reverse.luau local function reverse() -- etc end return reverse ``` -------------------------------- ### Avoid Luau String and Table Call Syntax Sugar Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md This guideline recommends against using Luau's syntactic sugar for string and table calls (e.g., `call "string"` or `call { stuff }`). These forms offer negligible readability improvements and are automatically reformatted by tools like StyLua to the traditional `call("string")` and `call({ stuff })` syntax, making their use unnecessary. ```Luau call "string" -- ...is equivalent to... call("string") call { stuff } -- ...is equivalent to... call({ stuff }) ``` -------------------------------- ### Concise and Actionable Comment in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates a rewritten, concise comment that provides immediate, actionable information relevant to the current code's usage. This improves readability and helps developers understand how to interact with the function. ```lua -- You can create a DamageInfo from just a number by using `createDamageInfo` local function dealDamage(victim: Player, damageInfo: DamageInfo) ``` -------------------------------- ### Performing Shallow Copy for Immutable Updates in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Shows how to perform a shallow copy in Luau using `table.clone` to immutably update a nested table. This approach avoids the performance overhead of deep copying by only cloning the necessary parts of the data structure. ```lua items = table.clone(items) items[1] = table.clone(items[1]) items[1].durability -= 10 ``` -------------------------------- ### Leveraging Luau `and` and `or` for Short-Circuiting and Defaults Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Explains that Luau's `and` and `or` operators return values (not booleans) and perform short-circuiting. This behavior is encouraged for assigning default values or conditionally executing code, providing concise and idiomatic solutions. ```Luau print(1 and 2) -- 2 print(1 or 2) -- 1 print(nil or "default") -- default print(nil and "second") -- nil ``` ```Luau local function f() print("calculating f...") return 100 end print(true and f()) -- prints "calculating f..." then 100 print(false and f()) -- never prints anything ``` ```Luau local function playSound(sound: Sound, volume: number?) local soundClone = sound:Clone() soundClone.Volume = volume or 0.5 -- Pick a reasonable default volume of 0.5 soundClone.Parent = SoundService soundClone:Play() end local function killPlayer(player: Player) -- It is even fine to chain local humanoid = player and player.Character and player.Character:FindFirstChild("Humanoid") if humanoid == nil then return end humanoid.Health = 0 end ``` -------------------------------- ### Dynamic Module Requiring (Avoid) in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates a dynamic `require` pattern in Luau, where module paths are determined at runtime. This approach prevents static type checking, resulting in `any` types for module values and eroding developer experience, especially in strict typing environments. ```lua local modules = {} for _, module in Modules:GetChildren() do modules[module.Name] = require(module) end return modules ``` -------------------------------- ### Unclear Optional Argument Syntax in Luau (Avoid) Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates a less readable way to define optional arguments in Luau, where the optionality (`?`) is applied to only a part of a union type. This can make the function signature harder to parse and understand at a glance. ```Luau local function useToggleState(default: boolean? | () -> boolean) ``` -------------------------------- ### Clear Optional Argument Syntax in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Provides clearer and more readable alternatives for defining optional arguments in Luau. By applying the optionality to the entire union type or explicitly including `nil` at the end, the intent of the argument's optionality becomes immediately apparent. ```Luau local function useToggleState(default: (boolean | () -> boolean)?) -- Also acceptable, sometimes more readable depending on the case, but `nil` should be at the end local function useToggleState(default: boolean | () -> boolean | nil) ``` -------------------------------- ### Refactoring nested conditionals with early returns in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Explains how to refactor deeply nested 'if' statements into a series of early 'return' statements for improved readability and maintainability in Luau. ```Luau if x then if y then if z then -- do something end end end ``` ```Luau if not x then return end if not y then return end if not z then return end -- do something ``` -------------------------------- ### Calculating Video Length with a C-style Function in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates a C-style function 'videoLength' that operates on the 'Video' type. This method avoids extending the 'Video' table with an enormous API surface, ensures type compatibility, and keeps the code simple and predictable. ```Luau -- videoLength.luau local function videoLength(video: Video.Video): number local total = 0 for _, slide in video.slides do total += slide.length end return total end ``` -------------------------------- ### Defining Luau Table Types for Data Structures Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates how to define C-style table types like 'Slide' and 'Video' in Luau. This approach is preferred over metatables for object definition to maintain type safety, reduce API surface, and simplify code. ```Luau type Slide = { length: number, -- assets... } type Video = { slides: { Slide }, } ``` -------------------------------- ### Module export patterns: Named variable vs. direct return in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Recommends exporting a named variable from a Luau module instead of directly returning an anonymous function. This practice improves code discoverability (e.g., Ctrl-Shift-F) and readability within the module itself. ```Luau -- perform.luau local function perform() -- code end return perform ``` ```Luau -- Another perform.luau return function() -- code end ``` -------------------------------- ### Use Absolute Paths and Avoid Excessive script.Parent in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md This guideline advocates for using absolute paths when requiring modules in Luau, as it enhances script portability and prevents exposing internal hierarchy details. While `script.Parent` is acceptable for sub-scripts following the 'implementation details' pattern, it should generally be avoided for navigation beyond one parent level. An exception is made for stories and tests, which are tightly coupled to their companion files and should use `script.Parent`. ```Luau -- ReplicatedStorage/Libraries/something.luau (Preferred absolute path) local library1 = require(ReplicatedStorage.Libraries.library1) ``` ```Luau -- Avoid this (relative path using script.Parent) local library1 = require(script.Parent.library1) ``` ```Luau -- Using FindFirstAncestor for a dynamic, yet absolute, root local Plugin = script:FindFirstAncestor("MyPlugin") local PluginButton = require(Plugin.Components.PluginButton) ``` -------------------------------- ### Luau Async Function Naming Convention Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates the convention of suffixing yielding functions with `Async` in Luau. This naming pattern clearly indicates asynchronous behavior, helping to prevent unexpected bugs in contexts sensitive to yielding, such as React. ```lua local function doThingAsync() local data = getDataAsync() act(data) end ``` -------------------------------- ### Avoid Specific Iteration Patterns in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Lists traditional Lua iteration constructs (`pairs`, `ipairs`, `next`) that should generally be avoided in Luau. These are often unnecessary due to Luau's generalized iteration feature, which simplifies loop syntax. ```Luau for i, v in pairs(t) do for i, v in ipairs(t) do for i, v in next, t do ``` -------------------------------- ### Static Module Requiring in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates a static `require` statement in Luau, where the module path is fixed. This allows Luau's static type checker to correctly infer types for the imported module, providing benefits like autofill and compile-time type errors. ```lua local Library = require(Modules.Library) return { Library = Library, } ``` -------------------------------- ### Providing Explicit Error Messages for Assertions in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates the recommended practice of providing a descriptive error message to Luau's `assert` function. This improves debugging by offering clear context when an assertion fails, unlike the generic message provided by default. ```lua assert(hasGold, "Player has no gold") ``` -------------------------------- ### Standardize `e = React.createElement` in Luau React Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md To improve readability in Luau React component creation, similar to JSX, it is a community standard to alias `React.createElement` to `e`. This idiom reduces verbosity and makes the component structure more apparent, enhancing code clarity. ```Luau local React = require(path.to.React) local e = React.createElement local MyComponent = function(props) return e("Frame", { Size = UDim2.fromScale(1, 1), BackgroundColor3 = Color3.new(1, 0, 0) }, { e("TextLabel", { Text = props.message, Size = UDim2.fromScale(0.5, 0.2) }) }) end ``` -------------------------------- ### Constant Error Messages in Luau Assertions vs. Rust Macros Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Compares how Rust's `assert!` macro handles formatted error messages efficiently by evaluating them only on failure, versus Luau's `assert` function which evaluates its error message every time. It advises against using interpolated strings for error messages in Luau due to performance overhead and suggests using an `if` block with `error` for dynamic messages. ```rust assert!(gold > 10, "Player has {gold} gold"); ``` ```lua assert(gold > 10, `Player has {gold} gold`) ``` ```rust if !(gold > 10) { panic!("Player has {gold} gold"); } ``` ```lua if gold < 10 then error(`Player has {gold} gold`) end ``` -------------------------------- ### Basic Assertions Without Error Messages Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates the default behavior of `assert` in Luau and Rust when no explicit error message is provided. It highlights the generic error output from Luau compared to Rust's more informative panic message, emphasizing the need for custom messages in Luau for better debugging. ```lua assert(hasGold) ``` ```rust assert!(has_gold); ``` -------------------------------- ### Using Luau If-Expressions for Ternary Logic Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md This section discusses the use of Luau's `if-expressions` as a first-class ternary operator. It notes that while explicit `== nil` checks are generally preferred, `if-expressions` can be used for concise conditional assignments, balancing readability with explicit checks. ```Luau local name = if character then character.Name else "Unknown" local name = if character == nil then "Unknown" else character.Name ``` -------------------------------- ### Define and Use String Enums in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Demonstrates how to define string-style enums using Luau's union types and how to use them in a function. This approach leverages Luau's type checker to prevent bugs statically, ensuring only valid enum values are used. ```Luau type Color = "red" | "blue" | "green" local function setColor(color: Color) if color == "red" then -- red elseif color == "blue" then -- blue elseif color == "green" then -- green end end -- To use: setColor("red") ``` -------------------------------- ### Demonstrate Runtime Errors with Library Enums in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Shows how using library-based enums can result in runtime errors when an invalid value is passed. This contrasts sharply with string enums, which would produce a static type error, allowing issues to be caught earlier in development. ```Luau setColor(Color.red) setColor(Color.pink) -- Runtime error! "pink" is not valid ``` -------------------------------- ### Avoid Library-Based Enum Creation in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Highlights a discouraged pattern for creating enums using a hypothetical `makeEnum` library function. This method is inferior to string unions because it lacks static type checking and proper autofill support, leading to runtime errors for invalid values. ```Luau local Color = makeEnum({ "red", "green", "blue" }) ``` -------------------------------- ### When to avoid early returns: Multiple independent effects in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates a scenario where early returns are not beneficial, specifically when a function performs multiple independent effects. Rewriting such a function with an early return can lead to unexpected behavior if new effects are added later. ```Luau local function performVictoryEffects(player, rewards) if rewards.cash > 0 then moneyExplosion(player) end if rewards.quality == "legendary" then playSoundEffect(player, WOAH_SOUND_EFFECT) end end ``` ```Luau local function performVictoryEffects(player, rewards) if rewards.cash > 0 then moneyExplosion(player) end if rewards.quality ~= "legendary" then return end playSoundEffect(player, WOAH_SOUND_EFFECT) end ``` -------------------------------- ### Avoid Commented-Out Code in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates commented-out code, which is considered noise and should be removed from the codebase. Version control systems are designed to track and retrieve previous versions of code, making commented-out sections redundant. ```lua dealDamage(victim, 100) -- dealDamage(victim, 50) ``` -------------------------------- ### Avoiding the `x and y or z` Ternary Pattern in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Warns against using the `x and y or z` pattern as a ternary in Luau, despite its historical use in Lua. This pattern can lead to unexpected behavior if the `y` value is falsy. It strongly recommends using Luau's explicit `if-then-else expressions` for ternary logic, reserving `or` for simple default assignments. ```Luau local goldAmount = giveDoubleGold and 1000 or 500 ``` ```Luau -- Don't give any gold on arena local goldAmount = gamemode == "arena" and nil or 100 ``` ```Luau local goldAmount = if gamemode == "arena" then nil else 100 ``` ```Luau local goldAmount = if gamemode.goldToGive then gamemode.goldToGive else 100 ``` -------------------------------- ### Appropriate Use of `typeof` Assertions in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Discusses the appropriate scenarios for using `assert(typeof(x) == "type")` in Luau. It advises against using them as a general 'just in case' measure in strictly typed code, reserving them for uncontrolled boundaries like user input from `RemoteEvents` or when dealing with unexpected values in otherwise strictly typed contexts. ```lua local function spendGold(player: Player, gold: number) assert(typeof(player) == "Instance" and player:IsA("Player"), "player isn't a Player") assert(typeof(gold) == "number", "Gold isn't a number") -- Do the rest... end ``` ```lua HurtMe.OnServerEvent:Connect(function(player, damage: number) assert(typeof(damage) == "number", "Player sent invalid damage") dealDamage(player, damage) end) ``` ```lua HurtMe.OnServerEvent:Connect(function(player, damage: number) -- Just adding some more code here... if damage < 0 then error("Player is trying to heal themselves!") end assert(typeof(damage) == "number", "Player sent invalid damage") dealDamage(player, damage) end) ``` ```lua HurtMe.OnServerEvent:Connect(function(player, damage: unknown) -- This code now statically errors, because you can't compare unknown with a number if damage < 0 then error("Player is trying to heal themselves!") end assert(typeof(damage) == "number", "Player sent invalid damage") -- damage is now narrowed to `number`. dealDamage(player, damage) end) ``` -------------------------------- ### Preferring Explicit Nil Checks over Truthiness in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md In Luau, values are 'falsy' if `false` or `nil`. This section advocates for explicit `~= nil` or `== nil` checks over implicit truthiness/falsiness in conditional statements to improve code clarity and intent, especially for inverse conditions. ```Luau if x.Parent then if x.Parent ~= nil then ``` ```Luau if not x.Parent then -- Bad if x.Parent == nil then -- Good ``` -------------------------------- ### Create an Exhaustive Match Utility Function in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Introduces a utility function `exhaustiveMatch` that can be used to ensure all cases in a conditional statement are handled. When used with union types, it helps the Luau type checker identify missing branches, preventing runtime errors. ```Luau local function exhaustiveMatch(value: never): never error(`Unknown value in exhaustive match: {value}`) end ``` -------------------------------- ### Discouraged String Enum Pattern in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Presents a pattern where string enums are wrapped in a table for access (e.g., `Color.red`). While seemingly convenient, this approach offers no additional benefits over direct string unions in a strictly typed Luau codebase and adds unnecessary complexity. ```Luau local Color = { red = "red" :: Color, green = "green" :: Color, blue = "blue" :: Color, } ``` -------------------------------- ### Avoid Trivial Type Annotations in Luau Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md This guideline advises against over-typing variables with trivial types (e.g., `number` for a number literal) unless it significantly aids readability, helps catch bugs statically, or is required by Luau for type narrowing. Excessive typing can introduce unnecessary noise into the codebase and complicate future refactoring efforts. ```Luau -- Bad! What bug could this possibly prevent? local MAX_HEALTH: number = 100 -- Bad! `item.attack` should return number, making this type pointless. local damage: number = item.attack(player) ``` -------------------------------- ### Avoid Hiding Luau Built-in Functions Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md This guideline advises against aliasing built-in functions (e.g., `table.insert`, `math.max`) to local variables. While previously an optimization, modern Luau makes inline usage equally or more performant. Hiding built-ins can also reduce code clarity, making it ambiguous whether a function is a standard built-in or a custom implementation. ```Luau local insert = table.insert local max = math.max local min = math.min ``` ```Luau -- Is `insert` some special function for our own collections? -- Is `items` a straight forward table, or is it an afformentioned special construct? -- The answer to both these questions would be "yes" if `insert` was any other function. insert(items, sword) -- Significantly more obvious. table.insert(items, sword) ``` -------------------------------- ### Fully Type Publicly Exposed Luau Functions Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md While Luau excels at type inference, it's crucial to fully type publicly exposed functions. This practice prevents subtle type errors that inference might miss and significantly improves API clarity, making it easier for other developers to understand and correctly use the function. Internal functions, however, can remain untyped or be optionally fully qualified. ```Luau -- attack.luau local function attack(player, item, target) local damage = item.attack(target) print(`{player} dealt {damage} damage!`) return damage end return attack -- Some other file -- Will probably work! attack(LocalPlayer, sword, enemy) ``` ```Luau local function attack(player: Player, item: Item, target: Attackable): number local damage = item.attack(target) print(`{player} dealt {damage} damage!`) return damage end ``` ```Luau -- This is internal, so it is okay not to type `player` and `damage` local function attackMessage(player, damage) print(`{player} dealt {damage} damage!`) end -- It would be equally acceptable to have written: -- local function attackMessage(player: Player, damage: number) local function attack(player: Player, item: Item, target: Attackable): number local damage = item.attack(target) attackMessage(player, damage) return damage end return attack ``` -------------------------------- ### Enforce Exhaustive Matching with Luau Enums Source: https://github.com/kampfkarren/kampfkarren-luau-guidelines/blob/main/README.md Illustrates how to integrate the `exhaustiveMatch` utility function into a function that processes enum values. If a new enum value is added and not handled, the type checker will flag the `exhaustiveMatch` call as an error, ensuring comprehensive handling. ```Luau local function setColor(color: Color) if color == "red" then -- red elseif color == "blue" then -- blue else -- TYPE ERROR! You forgot to match "green". exhaustiveMatch(color) end end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.