Roblox GuidebookKnowledge base
English ⌄

Development / ROBLOX

Luau functions: parameters, return and checking results

Learn to receive a function result, distinguish return from print, and validate inputs. Follow an original remaining-route-stops exercise with executable examples and boundary checks.

Updated:

Define the question before the function #

Imagine a teaching walk with ten stops. We know the total number of stops and how many have been visited. Our question is how many remain. The function answers an arithmetic question: subtract visited from total. It does not move a character, read saved progress or establish that a player actually visited any stop.

Write down the input meanings first. total is the complete stop count; visited is the visited count. For this exercise both must be nonnegative integers, with visited no greater than total. These are the exercise's rules, rather than a universal model for every Roblox route. Clear rules help identify whether an unexpected result comes from an input, the calculation or the expectation.

Define a function and call it #

The first example defines local function remainingStops(total, visited). Its body lies between the declaration and end. return supplies the calculated difference to the caller. Defining the function alone does not perform that calculation. Calling remainingStops(10, 3) starts execution with those two arguments.

Two calls save their results in separate variables. Ten total stops with three visited should give 7; ten with six visited should give 4. print then displays the saved values. Run the complete block in a separate teaching Script and compare the two Output lines with these expectations. The original examples were also executed with a standalone Luau interpreter; that verifies language behavior and arithmetic, rather than a playable Studio route.

Call and returned resultOpen full-size image ↗
Original calculation diagram; it does not establish game progress.
local function remainingStops(total, visited)
    return total - visited
end
local firstRemaining = remainingStops(10, 3)
local secondRemaining = remainingStops(10, 6)
print(firstRemaining)
print(secondRemaining)

Separate parameter names from supplied arguments #

total and visited name the parameters inside the function. The numbers 10 and 3 are arguments for one particular call. Another call supplies different values to the same parameters. An outside variable can be named routeLength without matching the parameter name, provided its value has the agreed meaning of total.

Order matters. remainingStops(10, 3) and remainingStops(3, 10) supply different inputs. The initial simple function does not validate their meaning, so the second call calculates a negative number. Changing the printed label will not repair that mistake. Compare the argument order and values with the input agreement before adding validation.

Observe why print does not replace return #

The second example, showRemaining, prints the difference inside its body. Calling it with 10 and 3 produces an Output line containing 7. However, it does not explicitly return a value. The caller's result variable receives nil. Consequently print(result) displays nil instead of printing the seven again.

A correct Output line therefore does not prove that the caller received the intended value. When later code needs the number, the calculation must return it. Keep both print calls for this exercise and observe the number from the function followed by nil from the caller. Substituting a constant seven hides the problem: another call must work with different inputs.

Output and result differOpen full-size image ↗
Original diagram distinguishing an Output message from a returned value.
local function showRemaining(total, visited)
    print(total - visited)
end
local result = showRemaining(10, 3)
print(result)

Keep the result where it is needed #

In the first example, firstRemaining and secondRemaining hold returned numbers. Calling code can compare them with expectations, pass them onward or display them. Calculation and presentation become separate steps. Saving the result in a local variable is enough to understand return; building an interface is not necessary for this exercise.

A return ends execution of that function branch. Do not put a further calculation after it in the same branch expecting it to change the returned value. Luau also supports returning multiple values separated by commas. Our checked example returns a pair: a result and a validity flag. This distinguishes an absent result from a successfully completed calculation.

Validate inputs before subtraction #

The third example, checkedRemaining, checks types first. A missing visited argument becomes nil, so the function returns nil, false before attempting arithmetic. It also rejects the string "10": the exercise accepts numbers and does not parse text input. Subsequent checks exclude NaN and positive infinity; negative values, including negative infinity, fail the negative-value check.

Checking the remainder after division by 1 rejects fractional counts. The last condition rejects visited greater than total. Only valid inputs reach return total - visited, true. This order makes each rule visible. It protects the teaching calculation from unsuitable inputs; it does not establish that a number supplied by a client represents genuine player progress.

local function checkedRemaining(total, visited)
    if type(total) ~= "number" or type(visited) ~= "number" then
        return nil, false
    end
    if total ~= total or visited ~= visited then
        return nil, false
    end
    if total == math.huge or visited == math.huge then
        return nil, false
    end
    if total < 0 or visited < 0 or total % 1 ~= 0 or visited % 1 ~= 0 then
        return nil, false
    end
    if visited > total then
        return nil, false
    end
    return total - visited, true
end
print(checkedRemaining(10, 3))
print(checkedRemaining(10))
print(checkedRemaining(10, 12))

Inspect missing and excessive progress #

The block contains three calls. checkedRemaining(10, 3) prints 7 and true. checkedRemaining(10) prints nil and false because the second argument is absent. checkedRemaining(10, 12) also prints nil and false: twelve visited stops do not fit a ten-stop route under our agreement.

Save both values with local value, valid = checkedRemaining(total, visited). Check valid == true before presenting the number. For false, prepare a clear invalid-data message. Automatically turning nil into zero hides the error and makes it resemble a completed route. Fix the input where it was formed instead of changing the failed calculation's meaning.

Recognize zero as a valid result #

checkedRemaining(10, 10) returns 0, true because all ten stops have been visited. The empty teaching route checkedRemaining(0, 0) also returns 0, true. Neither is an absent result. We reserve nil, false for rejected inputs, giving it a different meaning from the number zero.

Zero is truthy in Luau, but checking valid == true makes this function's agreement clearer. Testing only value > 0 would wrongly exclude a successful zero result. Any actual route-completion behavior belongs after the validity check and requires a game system that really uses this model.

Test boundaries as well as a successful call #

Create a matrix: 10 and 3 produce 7; 10 and 0 produce 10; 10 and 10 produce 0; 0 and 0 produce 0. Expect true for each. List invalid cases separately: a missing argument, a string instead of a number, a negative count, a fraction, and visited beyond total. Those should return nil and false.

The companion assertion file executed these cases and additionally checked NaN and infinity. Record expected results before running, then compare actual pairs. When they differ, report the precise input and observed pair. One successful call does not check every rule. Correct arithmetic also does not verify persistence, client trust or reward grants.

Input total / visitedExpected result
10 / 37, true
10 / 100, true
0 / 00, true
10 / missing second argumentnil, false

Hand over the function with its agreement #

Save the function name, parameter meanings and order, allowed inputs, returned pair and test matrix for the next developer. Label it as an original pure-Luau teaching example. When connecting a real route later, separately decide how the server obtains confirmed total and visited values and handles unavailable data.

This is not a completed progression or saving system: it contains no Roblox objects, events, networking or persistent storage. The useful outcome is understanding the difference between an Output message and a result available to the caller, and proving it with several understandable inputs. Expand the task while preserving that checked agreement.

FieldKeep
ParametersTotal and visited counts
RulesFinite nonnegative integers
ResultNumber and separate valid flag
ChecksNormal and boundary inputs

Original sources

Roblox Creator Hub — Functions