Language Reference: Variables

Defining, accessing, and updating variables


Defining Variables

We can use variables to store values. Variables in Pointless are defined using the assignment = operator. Variable names must be valid identifiers, and must not be keywords.

-- Store the string "Lilah" in the variable `name`
name = "Lilah"
name =
"Lilah"

Accessing Variables

After a variable is defined, it can be used by other pieces of code.

points = 90
total = 100

points / total
0.9

Reassigning Variables

Variables can updated after being initially defined. The syntax for reassigning an existing variable is the same as for defining a new variable.

score = 0
score = 1
score =
1

Compound Assignment

Sometimes we want to update an existing variable based on its current value, for example incrementing a score variable.

score = 0
score = score + 1
score =
1

We can simplify these sorts of updates using the compound assignment syntax, which combines a binary opeartor like + with the assignment operator =.

score = 0
score += 1 -- Equivalent to score = score + 1
score =
1

Compound assignment also works with pipeline operators.

cmpPct = 27 / 43
cmpPct |= Math.roundTo(3) -- Equivalent to cmpPct = Math.roundTo(cmpPct, 3)
cmpPct =
0.628

The available compound assignment operators are +=, -=, *=, /=, **=, %=, |=, $=, and ?=.


Variable Scope

Pointless is function-scoped, meaning that functions determine the scope of variables.

Variables defined outside of functions are globals, and can be accessed both by code within functions and code outside of functions.

pi = 3.14 -- Close enough

fn area(radius)
  pi * radius ** 2 -- We can use the global `pi` within the function
end

area(5)
78.5

Variables defined inside a function, including function parameters, are locals, and are only accessible withing that function.

fn distance(x1, y1, x2, y2)
  -- `dx` and `dy` are only defined within the function
  dx = x1 - x2
  dy = y1 - y2
  Math.sqrt(dx ** 2 + dy ** 2)
end

distance(0, 0, 3, 4)

-- Incorrect, we can't access `dx` outside of `distance`
dx
5
Error: variable is not defined

Function-scoping means that control structures like conditionals and loops don't create new scopes. Variables defined within these control structures (including loop variables) will be accessible outside of the structures.

numbers = [1, 2, 3, 4, 5]
total = 0

for n in numbers do
  total += n
end

total
n
15
5

Shadowing

Local variables with the same names as globals will shadow those globals. Defining a local variable inside a function will not change the value of a global variable with the same name.

greeting = "Hello"

fn sayHi()
  -- Changes the value of `greeting` within the function, making a new local
  -- definition and leaving the global definition for `greeting` unchanged
  greeting = "hi"
  "$greeting world!"
end

sayHi()
greeting -- Value of the global variable hasn't changed
"hi world!"
"Hello"

When a function defines a local variable that shadows a global, code in the function won't have access the global definition, even if the variable access precedes the local definition.

greeting = "Hello"

fn sayHi()
  -- Invalid, local variable `greeting` is not yet defined and
  -- global `greeting` is shadowed and therefore inaccessible
  print(greeting)
  greeting = "hi"
end

sayHi()
Error: variable has not been defined yet

Structural Updates

In Pointless, we can use assignment syntax to update variables containing lists, objects, and tables.

hero = { name: "Lilah", score: 0, items: [none] }

hero.score += 1 -- Increment the `score` value in `hero`
hero.items[0] = "food" -- Replace the first value in the `items` list in `hero`
hero =
{ name: "Lilah", score: 1, items: ["food"] }

Note that structural updates like these are still just variable reassignments; they do not mutate the underlying data structures like they would in other languages. See the chapter on immutability for more details.