# Getting started with SwiftLua

This is a gentle, hands-on introduction to writing SwiftLua scripts. You don't need to
know Lua. If you've written a little JavaScript or TypeScript, you already know most of
the ideas, and this guide points out the few differences as it goes. When you want the
precise rules for anything here, the [Language Guide](#language) is the full
reference.

In the examples, `-->` shows what a line produces:

```lua
local answer = 6 * 7
answer  --> 42
```

## What you're writing

A SwiftLua script is a small program that runs **inside an app**, safely. The app gives
your script some **inputs**, your script works something out, and it hands back a result
with `return`. A script can't reach files, the network or the clock unless the app gives
it a function for that, and it always finishes, because the app sets time and memory
limits.

Think of a script as a function the app calls: inputs in, a value out.

## If you've written JavaScript or TypeScript

Most of your instincts carry over:

| You know (JS/TS) | In SwiftLua |
|---|---|
| `let x = 1` / `const x = 1` | `local x = 1` (always `local`; there's no `var`) |
| `// comment` | `-- comment` |
| `===` / `!==` | `==` / `~=` (note: `~=`, not `!=`) |
| `&&` / `\|\|` / `!` | `and` / `or` / `not` |
| `a + b` to join strings | `a .. b` (`..` joins; `+` is for numbers only) |
| `null` / `undefined` | `nil` (just one) |
| `obj.field`, `arr[0]` | `obj.field`, `arr[1]` (**arrays start at 1**) |
| objects `{}` and arrays `[]` | both are **tables** `{}` (one type, two uses) |
| `x: number`, `"a" \| "b"`, `T \| null` | `x: number`, `"a" \| "b"`, `T?`: TypeScript-style types, **checked before the script runs** |
| `try { } catch { }` | `pcall(...)` (covered below) |

The differences that trip people up are collected in the
[cheat-sheet](#gotchas-cheat-sheet) at the end. Skim it once and you'll avoid the common
surprises.

## Your first script

Say the app runs your script with an `order` input and wants the total price, with a 10%
discount once the subtotal passes 100. Here's the whole thing:

<!-- example {"inputs": {"order": {"lines": [{"qty": 2, "price": 40}, {"qty": 1, "price": 35}]}}, "returns": 103.5} -->
```lua
local subtotal = 0
for _, line in ipairs(order.lines) do
  subtotal = subtotal + line.qty * line.price
end

local discount = 0
if subtotal > 100 then
  discount = subtotal * 0.1
end

return subtotal - discount
```

For an order of two items at 40 and one at 35, it returns 103.5. Line by line:

- `order` is an **input the app supplied**; you just use it.
- `ipairs(order.lines)` loops over the array `order.lines` in order. `_` is the position
  (not needed here) and `line` is each element.
- `local` makes a variable, and `=` assigns to it.
- `return` hands your result back to the app.

That's a real script. Everything below is more building blocks.

## The building blocks

### Variables

```lua
local total = 0
local name, qty = "widget", 3   -- declare several at once
total = total + 1               -- assign (there is no ++ or +=)
total  --> 1
```

Always use `local`. Assigning to a name you never declared (`total = 1` with no `local`)
creates a *global*, which the checker reports as an error, because it's almost always a
typo. Reading a name that doesn't exist is an error too, where JavaScript would quietly
give you `undefined`.

### Numbers and strings

```lua
local n = 10
local r = 10 / 4
r  --> 2.5
local s = "qty=" .. n
s  --> "qty=10"
```

`/` always gives a decimal result, and `..` turns numbers into text for you. Integers and
decimals are distinct, and integer arithmetic that overflows **stops with an error**
instead of silently wrapping round. You'll rarely hit it, but it's why results can be
trusted.

### Tables: objects *and* arrays

A table is the only container. It's both your "object" and your "array":

```lua
local person = { name = "Ada", age = 36 }   -- like a JS object
person.name     --> "Ada"
person["age"]   --> 36

local items = { "a", "b", "c" }              -- like a JS array
items[1]        --> "a"
#items          --> 3
```

Arrays start at 1, not 0, and `#` gives the length. You can mix the two uses in one table,
but typed code is clearer when arrays and records stay separate.

### Conditionals and loops

```lua
local score = 85
local grade
if score > 90 then
  grade = "A"
elseif score > 80 then
  grade = "B"
else
  grade = "C"
end
grade  --> "B"

local sum = 0
for i = 1, 5 do sum = sum + i end          -- 1 through 5, inclusive
sum  --> 15

local letters = ""
for _, v in ipairs({ "x", "y", "z" }) do   -- each array element, in order
  letters = letters .. v
end
letters  --> "xyz"

local fields = 0
for key, value in pairs({ name = "Ada", age = 36 }) do   -- every key and value
  fields = fields + 1
end
fields  --> 2
```

Note that `for i = 1, 5` includes 5: ranges include both ends.

### Functions

```lua
local function area(w, h)
  return w * h
end

area(3, 4)  --> 12
```

A function can return **more than one value**. It's handy for "a result and an error",
and reads like destructuring a tuple in TypeScript:

```lua
local function divmod(a, b)
  return a // b, a % b   -- // is whole-number division
end

local q, r = divmod(17, 5)  --> q = 3, r = 2
```

There are a few precise rules about multiple values (Language Guide §4), but the common
case is exactly this.

## Types: like TypeScript, checked before the script runs

You can annotate variables, parameters and return types, and a checker verifies them
**before the script runs**, so typos and mismatched types are caught up front rather than
halfway through.

```lua
local total: number = 0
local names: {string} = {}                   -- array of strings
local rates: {[string]: number} = { GBP = 1.25 }   -- map: string keys to numbers
local status: "open" | "closed" = "open"     -- only these two values allowed
local note: string? = nil                    -- optional: a string or nil

local function convert(amount: number, code: string): number
  return amount * (rates[code] or 1)
end

convert(10, "GBP")  --> 12.5
```

Unions, literal types, optionals (`T?`), arrays (`{T}`), maps (`{[K]: V}`) and function
types (`(number) -> number`) are all there. You can name your own shapes too:

```lua
type Line  = { sku: string, qty: number }
type Order = { lines: {Line}, status: "open" | "closed" }

local function units(order: Order): number
  local count = 0
  for _, line in ipairs(order.lines) do count = count + line.qty end
  return count
end

units({ lines = { { sku = "A", qty = 2 }, { sku = "B", qty = 3 } }, status = "open" })  --> 5
```

The checker also **narrows** types as your code tests them, just like TypeScript:

```lua
local function describe(value: number | string): string | number
  if type(value) == "string" then
    return value .. "!"     -- here the checker knows value is a string
  else
    return value + 1        -- and here it's a number
  end
end

describe("hi")  --> "hi!"
describe(1)     --> 2
```

Types are optional: start without them and add them as you go. The checker is strict by
default; putting `--!nonstrict` on the first line turns type findings into warnings while
you're learning (Language Guide §9).

## Working with the app

Your script reaches the outside world only through what the app provides. Which inputs,
functions and modules exist depends on the app, and its own documentation lists them. The
names below are examples.

- **Inputs and data**: values the app sets, like `order` above. Just read them.
- **Functions the app gives you**, sometimes grouped under a name, such as
  `orders.fetch(1042)`. You call them like any other function. Some do real work (reading
  a database, calling a web service) and wait briefly while they do; that happens by
  itself, with no special syntax (Language Guide §12).
- **Modules**: `local helpers = require("helpers")` loads a script the app makes
  available, usually a table of functions.
- **Your result**: whatever you `return`.

A function from the app might return a value *and* an error, which you read as a pair:

```lua
local qty, err = parseQuantity("12")
qty  --> 12
err  --> nil

local bad, problem = parseQuantity("twelve")
bad      --> nil
problem  --> "not a quantity"
```

## When things go wrong

- **Errors** stop the script: `error("bad input")`, a failed `assert(condition, "message")`,
  or a mistake at run time such as calling something that isn't a function. The app
  receives a clear error, with the line it happened on.
- **Catching errors** uses `pcall`, SwiftLua's `try`/`catch`:

  ```lua
  local function risky()
    error("out of stock", 0)
  end

  local ok, result = pcall(risky)
  ok      --> false
  result  --> "out of stock"
  ```

- **Limits** are set by the app: a script can't loop forever or use unlimited memory. If
  it reaches a limit, the run ends with an error saying which one, and `pcall` *cannot*
  catch it. That's deliberate: it keeps the app safe.

## Gotchas cheat-sheet

The handful of things that surprise people coming from JavaScript:

1. **Arrays start at `1`.** `items[1]` is the first element; `#items` is the length.
2. **`0` and `""` count as true.** Only `nil` and `false` are false, so `if 0 then` runs.
3. **`..` joins strings, not `+`.** `"a" + "b"` is an error; `"a" .. "b"` is `"ab"`.
4. **`~=` means "not equal"** (not `!=`), and it's `and`/`or`/`not`, not `&&`/`||`/`!`.
5. **No `++`, `+=` or `var`.** Write `x = x + 1`, and always use `local`.
6. **Reading an unknown variable is an error**, not `undefined`. That catches typos.
7. **`nil` is the only "empty".** There's no separate `null` and `undefined`.
8. **One container type.** `{}` is an object or an array depending on how you use it.
9. **Integer overflow is an error** rather than wrapping round, so results stay correct.
10. **`print` may not exist**, depending on the app. `return` is how you give back a
    result.

## Where to go next

The [Language Guide](#language) is the full reference. Useful places to jump to:

- Multiple return values, the exact rules: §4
- Tables, iteration order and the class pattern: §5
- Modules and `require`: §6
- The standard library (math, string, table and set helpers, time, UUIDs): §8
- The extra libraries (json, hash, url, csv, decimal, stats, template and more), where
  the app offers them: [Extra libraries](#libraries)
- The type system in depth (enums, exhaustiveness, narrowing): §9
- Errors and limits: §10
- Objects the app provides: §11
- Functions that wait on the outside world: §12

You don't need all of it to be productive. Come back when a specific question comes up.
Happy scripting.