---
url: /programming-fundamentals/functions-and-scope.md
description: Define and call functions, pass arguments, return values, and master scope.
---

# Functions and Scope

*Written: {{ $frontmatter.date }}*

## Learning objectives

* You define functions and call them.
* You tell parameters apart from arguments.
* You return values, including more than one.
* You explain [scope](https://create.roblox.com/docs/luau/scope), upvalues, and shadowing.
* You store functions in variables like any other value.

## Prerequisites

* Read [First Script](../getting-started/first-script.md). You can run a Script and read output.
* Read [Variables and Values](variables-and-values.md). You create variables with `local`.
* Read [Operators and Logic](operators-and-logic.md). You compute and compare values.
* Read [Conditionals and Loops](conditionals-and-loops.md). You branch with `if`.

## Define a function, then call it

A function is a named block of code that runs when you call it. You define it once and call it as often as you like. Defining uses the word `function`, a name, parentheses, a body, and `end`. Calling uses the name plus parentheses.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local function greet()
	print("Hello!")
end
greet()
greet()
```

```txt
Hello!
Hello!
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 defines a function named `greet`. Nothing runs yet. Defining only teaches Luau the steps.
3. Line 3 is the body. It prints `"Hello!"` each time the function runs.
4. Line 4 ends the definition.
5. Line 5 calls `greet` for the first time, printing `Hello!`.
6. Line 6 calls it again, printing `Hello!` a second time.

Always define with `local function`. The `local` keeps the name inside your script, exactly like variables. Name functions in camelCase with a verb first, like `greetPlayer` or `addBonus`.

## Parameters receive, arguments deliver

Parameters and arguments are two sides of one handoff. Parameters are the placeholder names listed in the definition. Arguments are the real values you pass at the call. Think of parameters as labeled cups, and arguments as what you pour into them.

Two rules protect you. Extra arguments are dropped silently. Missing arguments arrive as [nil](https://create.roblox.com/docs/luau/nil).

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local function greetPlayer(playerName)
	print("Hi, " .. playerName)
end
greetPlayer("Maya")
greetPlayer("Rio")
```

```txt
Hi, Maya
Hi, Rio
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 defines `greetPlayer` with one parameter, `playerName`. It holds no value yet.
3. Line 3 joins `"Hi, "` with whatever `playerName` holds and prints it.
4. Line 4 ends the definition.
5. Line 5 calls with the argument `"Maya"`. Luau pours `"Maya"` into `playerName` and prints `Hi, Maya`.
6. Line 6 calls with `"Rio"`. The parameter now holds `"Rio"` and prints `Hi, Rio`.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local function addBonus(score, bonus)
	print(score + bonus)
end
addBonus(10, 5)
addBonus(10, 5, 99)
```

```txt
15
15
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 defines `addBonus` with two parameters, `score` and `bonus`.
3. Line 3 prints their sum.
4. Line 4 ends the definition.
5. Line 5 passes `10` and `5`. The sum `15` prints.
6. Line 6 passes a third argument, `99`. Luau drops it silently, so `15` prints again.

## Send answers back with return

`print` shows a value to you. `return` hands a value back to the caller. The caller can store it, print it, or feed it into more math. `return` also ends the function at once. Nothing after it in the same block runs.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local function double(amount)
	return amount * 2
end
local doubled = double(7)
print(doubled)
print(double(3))
```

```txt
14
6
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 defines `double` with parameter `amount`.
3. Line 3 returns `amount * 2` to the caller and ends the function.
4. Line 4 ends the definition.
5. Line 5 calls `double(7)`, stores the returned `14` in `doubled`.
6. Line 6 prints `14`.
7. Line 7 calls `double(3)` and prints the returned `6` directly.

A function can return more than one value. List them after `return` with commas, and catch them in the same order. This is handy when one computation produces a pair, like a sum and a difference.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local function addAndSubtract(first, second)
	return first + second, first - second
end
local total, gap = addAndSubtract(9, 4)
print(total)
print(gap)
```

```txt
13
5
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 defines `addAndSubtract` with two parameters.
3. Line 3 returns two values: the sum and the difference.
4. Line 4 ends the definition.
5. Line 5 calls with `9` and `4`. Luau assigns `13` to `total` and `5` to `gap`.
6. Lines 6 and 7 print `13` then `5`.

A function with no `return` gives back `nil`. That is normal for functions that only do something, like printing.

## Scope decides what code can see

Scope is the region of code where a name exists. A `local` name lives in the block where you declared it, from that line down to the block's `end`. A block is the body of a function, an `if`, or a loop. Outer blocks cannot see names declared in inner blocks. Inner blocks can read names from outer blocks.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local title = "Coach"
local function announce()
	local message = "Team huddle!"
	print(title)
	print(message)
end
announce()
print(title)
```

```txt
Coach
Team huddle!
Coach
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 declares `title` at the top level, so the whole script can see it.
3. Line 3 defines `announce`.
4. Line 4 declares `message` inside the function. Only the function can see it.
5. Line 5 prints `title`. The function reads outward and finds it. This prints `Coach` first.
6. Line 6 prints `message`. This prints `Team huddle!` second.
7. Line 7 ends the function.
8. Line 8 calls `announce`, producing the first two output lines.
9. Line 9 prints `title` again, producing the final `Coach`.

Order matters here. `Coach` prints first because line 5 runs before line 6. If you tried `print(message)` on line 9 instead, you would get `nil`, because `message` does not exist outside the function.

When a function reads an outer `local`, programmers call that outer variable an upvalue. The function captures it. This is how small helper functions share data without globals.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local cheer = "Go team!"
local function chant()
	print(cheer)
end
chant()
```

```txt
Go team!
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 declares `cheer` outside the function.
3. Line 3 defines `chant`.
4. Line 4 prints `cheer`. Here `cheer` is an upvalue: an outer local captured by the function.
5. Line 5 ends the function.
6. Line 6 calls `chant`, printing `Go team!`.

Shadowing happens when an inner block declares its own `local` with the same name as an outer one. The inner name wins inside its block. The outer one is untouched. Shadowing is legal but confusing, so treat a shadowed name as a smell and rename one of them.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local points = 5
local function showPoints()
	local points = 99
	print(points)
end
showPoints()
print(points)
```

```txt
99
5
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 declares outer `points` as `5`.
3. Line 3 defines `showPoints`.
4. Line 4 declares a new inner `points` set to `99`. This shadows the outer one.
5. Line 5 prints the inner `99`.
6. Line 6 ends the function.
7. Line 7 calls it, printing `99`.
8. Line 8 prints the outer `points`, still `5`. The inner assignment never touched it.

## Functions are values

In Luau, a function is a value like a number or a string. You can store it in a variable and pass it around under a new name. The variable holds the function itself, not a copy of its result. Add parentheses to run it.

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local function cheerLoud()
	print("Go!")
end
local myCheer = cheerLoud
myCheer()
```

```txt
Go!
```

Walkthrough:

1. Line 1 turns on strict mode.
2. Line 2 defines `cheerLoud`.
3. Line 3 prints `"Go!"` when called.
4. Line 4 ends the definition.
5. Line 5 stores the function itself in `myCheer`. No parentheses means no call yet.
6. Line 6 calls the function through `myCheer`, printing `Go!`.

This idea powers events and callbacks later in the course. A system can keep your function in a variable and call it when something happens. For now, remember: parentheses run, no parentheses refer.

## Common mistakes

**Calling before defining.**

Run this to see it fail: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
greet()
local function greet()
	print("Hello!")
end
```

```txt
ServerScriptService.Script:2: attempt to call a nil value
```

On line 2, `greet` does not exist yet, so calling it fails. Fix it by defining first, calling after. Run the fix the same way.

```luau
--!strict
local function greet()
	print("Hello!")
end
greet()
```

```txt
Hello!
```

**Confusing parameters with arguments.**

Run this to see it fail: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local function greetPlayer(playerName)
	print("Hi, " .. playerName)
end
greetPlayer()
```

```txt
Red error on line 3: you cannot join nil with "..". No argument arrived, so playerName is nil.
```

No argument arrived, so `playerName` is `nil` and `..` cannot join `nil`. Fix it by passing an argument. Run the fix the same way.

```luau
--!strict
local function greetPlayer(playerName)
	print("Hi, " .. playerName)
end
greetPlayer("Maya")
```

```txt
Hi, Maya
```

**Printing instead of returning.**

Run this to see it fail: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local function double(amount)
	print(amount * 2)
end
local doubled = double(7)
print(doubled + 1)
```

```txt
14
ServerScriptService.Script:6: attempt to perform arithmetic (add) on nil and number
```

Line 6 prints `14` first, then the error hits: `double` returns `nil`, and `nil + 1` is illegal. Fix it by returning the result. Run the fix the same way.

```luau
--!strict
local function double(amount)
	return amount * 2
end
local doubled = double(7)
print(doubled + 1)
```

```txt
15
```

**Reading an inner variable from outside.**

Run this: put it in a Script in ServerScriptService and press Play.

```luau
--!strict
local function announce()
	local message = "Team huddle!"
end
announce()
print(message)
```

```txt
nil
```

This prints `nil` because `message` lives only inside the function. Fix it by returning the value and storing it outside. Run the fix the same way.

```luau
--!strict
local function announce()
	return "Team huddle!"
end
local message = announce()
print(message)
```

```txt
Team huddle!
```

## Exercises

Run every solution below in a Script in ServerScriptService and press Play. Try each exercise yourself before you open its solution.

1. Define `sayReady` that prints `"Ready!"`. Call it twice.

::: details Solution 1

```luau
--!strict
local function sayReady()
	print("Ready!")
end
sayReady()
sayReady()
```

```txt
Ready!
Ready!
```

:::

2. Define `welcome` with one parameter `playerName`. It prints `"Welcome, "` joined with the name. Call it with `"Rio"`.

::: details Solution 2

```luau
--!strict
local function welcome(playerName)
	print("Welcome, " .. playerName)
end
welcome("Rio")
```

```txt
Welcome, Rio
```

:::

3. Define `triple` that returns its argument times `3`. Store the result of `triple(4)` in a variable and print it.

::: details Solution 3

```luau
--!strict
local function triple(amount)
	return amount * 3
end
local tripled = triple(4)
print(tripled)
```

```txt
12
```

:::

4. Define `splitBill` that takes `total` and `friends` and returns two values: each share (`total / friends`) and the leftover (`total % friends`). Call it with `100` and `4`. Print both results.

::: details Solution 4

```luau
--!strict
local function splitBill(total, friends)
	return total / friends, total % friends
end
local share, leftover = splitBill(100, 4)
print(share)
print(leftover)
```

```txt
25
0
```

Line 2 returns both values at once. Line 5 catches them in order into `share` and `leftover`.

:::

## Summary

You defined functions with `local function` and called them with parentheses. You passed arguments into parameters, remembered that extras drop and missing ones arrive as nil, returned single and multiple values, read outer locals as upvalues, spotted shadowing, and stored functions in variables.

Next: [Tables, Part 1](tables-part-1.md).
