Quirrel4.41.0

Coming from Lua

Both languages are small, embedded, dynamically typed and reference counted, and both are made to be driven from C. The differences are around tables: an array and a table are separate types, indices start at 0, a missing key is an error rather than nil, and no name is global unless you declare it global.

The syntax is the C family: braces, !=, &&, // for a comment.

Values and bindings

LuaQuirrel
local x = 1local x = 1 - rebindable; let x = 1 - binds once
a name with no local is globalthere are no implicit globals; every name is declared
nilnull
x == nilx == null
~=!=
..$"{a}{b}", or concat; + joins too, and the analyzer flags it as w264
#s, #ts.len(), t.len()
and, or, not&&, ||, !, and they keep the operand value
one number typeinteger and float; 7 / 2 is 3, 7 / 2.0 is 3.5
// floor division/ on two integers, which truncates; // starts a comment
-7 % 3 is 2-1; the sign follows the left side, as in C
tostring(x), tonumber(s)x.tostring(), s.tointeger(), s.tofloat()
string.format(...)format(...) from string
[[two lines]]@"two lines", a verbatim string with no escapes
-- comment// comment or /* ... */

Tables and arrays

LuaQuirrel
{ 1, 2, 3 }, keys 1 to 3[1, 2, 3], an array, and its first index is 0
{ a = 1 }{ a = 1 }, a table, with = inside
t.k = v on a new keyt.k <- v; plain = writes a slot that is already there
t.k on a missing key gives nilit throws; t?.k gives null, and ?? fills in
t[k] = nil removes the keyit stores null and keeps the slot; t.$rawdelete(k) removes
#aa.len()
table.insert(a, v)a.append(v), and it takes several values
table.insert(a, 1, v)a.insert(0, v)
table.remove(a, i)a.remove(i)
table.remove(a)a.pop()
table.concat(a, ",")",".join(a), which is a string method
table.sort(a, cmp)a.sort(cmp), with @(x, y) x <=> y
pairs(t)foreach (k, v in t)
ipairs(a)foreach (v in a), or foreach (i, v in a) for the index too
next(t)not there; use foreach
s:sub(2, 3), 1-based and inclusives.slice(1, 3), 0-based and end exclusive
s:find(sub)s.indexof(sub), and null when the text is not there
s:gsub(a, b) for plain texts.replace(a, b), and it replaces every match
a Lua patternregexp("[0-9]+") from string
setmetatable(t, mt)not there; a class carries the metamethods
mt.__indexa base class, or the _get metamethod
mt.__add, mt.__tostring_add, _tostring, on a class

Control flow and functions

LuaQuirrel
if a then ... elseif b ... endif (a) { } else if (b) { } else { }
for i = 1, n dofor (local i = 0; i < n; i++)
while c do ... endwhile (c) { }
repeat ... until cdo { } while (!c)
gotonot there
function f(a) endfunction f(a) { }
local function f()function f() is already local to the file
function t.m(a)let t = { function m(a) { } }
function t:m(a) and selffunction m(a) in a table or class, and this
t:m(x)t.m(x)
return a, breturn an array: return [a, b], read as let [a, b] = f()
... and select("#", ...)function f(...) and vargv.len()
f{ ... } and f"..."not there; a call always has parentheses
pcall(f)try { f() } catch (e) { }; a pcall here is a call that skips the error handler, and it does not catch
error("m")throw "m"; any value can be thrown, and catch takes them all
coroutine.create(f)newthread(f)
coroutine.resume(co, v)th.call(v) the first time, th.wakeup(v) after that
coroutine.yield(v)suspend(v) in a thread, yield v in a generator
require "m"require("m"), or import "m" at compile time
os.clock()clock() from datetime
io.write(s)print(s), or println(s) with a newline
os.getenv(n)getenv, in the system module

Traps

examples/pages/coming-from/lua.nut
// indices start at 0, and an array is its own type
let squad = ["alpha", "bravo"]
println(squad[0])
println(squad.len())

// + joins as soon as one side is a string; it never reads a number out of one
println("10" + 1)
println("10".tointeger() + 1)

// a stored null keeps the slot, so removing one needs rawdelete
let ammo = { rifle = 30 }
let key = "rifle"
ammo.rifle = null
println($"after null:      len={ammo.len()} has {key}={key in ammo}")
ammo.$rawdelete(key)
println($"after rawdelete: len={ammo.len()} has {key}={key in ammo}")

// % takes its sign from the left side, as in C
println(-7 % 3)
Output:
alpha
2
101
11
after null:      len=1 has rifle=true
after rawdelete: len=0 has rifle=false
-1

What is not there

See also