Variables and scope
A variable is a name that holds a value. You create one by assigning to it. There is no declaration and no type.
Assignment
Section titled “Assignment”There are two spellings of plain assignment. They mean the same.
set greeting to "Hello"set other to "Hi"set third = "Hey"printline greetingprintline otherprintline thirdHelloHiHeygreeting = "Hello"other = "Hi"set third = "Hey"printline(greeting)printline(other)printline(third)HelloHiHeyset name to value and set name = value and name = value all work. The target can be a name, a property (file.status = "x"), or an index (list[0] = 1). Anything else is a syntax error: Invalid assignment target.
Assigning replaces whatever the variable held. The old value is discarded.
Arrays and dictionaries are copied on assignment, so two variables never share one. See Values and types.
Compound assignment
Section titled “Compound assignment”+=, -=, *= and /= change a variable using its own value. The natural form is a keyword: increment, decrement, multiply and divide, each with an optional by. Without by the amount is 1.
set x to 3increment x by 2printline xincrement xincrement x by 10decrement x by 2multiply x by 2divide x by 4printline x57x = 3x += 2printline(x)x += 1x += 10x -= 2x *= 2x /= 4printline(x)57Appending
Section titled “Appending”name[] = value adds an item to the end of an array. It works on a name, on an index, and on a property: a[] = 1, a[2][] = 1, a.list[] = 1.
set list to []list[] = "a"list[] = "b"printline count(list)2list = []list[] = "a"list[] = "b"printline(count(list))2Assignment inside a condition
Section titled “Assignment inside a condition”An if, while, until or ensure can assign and test in one step. The condition is true when the assigned value is true.
if first = mash.collect([7, 8]).first() printline "first is {{first}}"endfirst is 7if first = mash.collect([7, 8]).first() { printline("first is {{first}}")}first is 7Several assignments can be joined with and, or or a comma. A comma means and here.
Reading a variable
Section titled “Reading a variable”Reading a name that was never set gives null. It is not an error. A misspelt name therefore looks like a variable that is empty.
set total to 5printline "[{{totl}}]"[]total = 5printline("[{{totl}}]")[]A script has one global space, and each call of a block has its own local space. These rules decide which one a name belongs to.
Reading
Section titled “Reading”A name is looked up in this order:
- the block’s parameters
- the block’s own
herevariables - the parameters and
herevariables of the blocks that enclose it - the global variables
If the name is none of these, it can be a block with no parameters, which is then called. Otherwise the value is null.
A block can therefore read every global variable.
Writing
Section titled “Writing”Assigning to a name writes to the place where the name already lives, using the same order as reading. If the name is nowhere, the assignment creates a global variable.
That is the rule that surprises people. A plain assignment inside a block does not make a local variable. It changes the global one, or creates one that is still there after the block ends.
set total to 0block add n increment total by n set created to "visible outside"endadd(5)add(6)printline totalprintline created11visible outsidetotal = 0block add(n) { total += n created = "visible outside"}add(5)add(6)printline(total)printline(created)11visible outsideA parameter is local. Changing it does not change the caller’s variable.
block bump p set p to p + 1 return pendset p to 10printline bump(1)printline p210block bump(p) { p = p + 1 return p}p = 10printline(bump(1))printline(p)210here: a variable of one call
Section titled “here: a variable of one call”here name = value makes a variable that belongs to the current call of the block. It is not visible to the caller and does not outlive the call. Later plain assignments to the same name inside the block change the local one.
set x to 1block f here x = 2 set x to 3 return xendprintline f()printline x31x = 1block f() { here x = 2 x = 3 return x}printline(f())printline(x)31block f here secret = 1endf()printline "[{{secret}}]"[]block f() { here secret = 1}f()printline("[{{secret}}]")[]If a parameter has the same name, here replaces the parameter’s value for that call.
here also works inside a condition: if here found = lookup(name).
Each call gets fresh locals, so a block that calls itself does not disturb its caller’s variables.
A block defined inside another block can read the outer block’s here variables and parameters:
block outer here a = 1 block inner return "inner sees a=[{{a}}]" end return inner()endprintline outer()inner sees a=[1]block outer() { here a = 1 block inner() { return "inner sees a=[{{a}}]" } return inner()}printline(outer())inner sees a=[1]At the top level of a script, here makes a variable that blocks can read but is otherwise like a global.
Loop variables
Section titled “Loop variables”The variable named in each ... as name is an ordinary variable. It is not scoped to the loop. It keeps the last value after the loop ends, and it overwrites a variable of the same name.
set i to "before"each 1...3 as i # i is reassigned on each passendprintline i3i = "before"each (1...3) as i { # i is reassigned on each pass}printline(i)3Names that mean two things
Section titled “Names that mean two things”A block and a variable can share a name. This is not an error. The variable wins once it has been set, and the bare name calls the block until then.
block name return "from block"endset x to nameprintline xset name to "now a variable"printline namefrom blocknow a variableblock name() { return "from block"}x = nameprintline(x)name = "now a variable"printline(name)from blocknow a variableBuilt-in names
Section titled “Built-in names”mash and event always refer to the built-in objects, so a script cannot assign to them. The compiler refuses the script. value is the loop variable that each uses when you give no as name.
The built-in blocks print, printline, send, sendline, sendheader, sendstatus, sleep, uppercase, lowercase and explain can be called by name. Any method of the mash object can also be called without the mash. prefix, so count(list) is the same as mash.count(list).
printline count([1, 2, 3])printline mash.count([1, 2, 3])33printline(count([1, 2, 3]))printline(mash.count([1, 2, 3]))33