Differences from Squirrel language
Squirrel language was used a lot in all Gaijin projects since 2006. Gaijin used Lua before but found Lua too unsafe and hard to debug, and also hard sometimes to bind with native code due to lack of types. It is well known and there are lot info on this in the Internet. Squirrel has not only C++ like syntax (which is helpful for C++ programmers sometimes), but also has type system much closer to CC++ code. It also has safer syntax and semantic. However during heavy usage we found that some features of language are not used in our real codebase of millions of LoC in 20+ projects on 10+ platforms. Some language features were also not very safe, or inconsistent. We needed stricter language with tools for easier refactor and support. And of course in game-development any extra performance is always welcome. Basically in any doubt we used ‘Zen of Python’.
We renamed language from Squirrel to Quirrel to avoid ambiguity.
New features
Check for conflicting local variable, local functions, function arguments and constant names
Check for conflicting table slots declaration
Null propagation, null-call and null-coalescing operators
‘not in’ operator
Destructuring assignment
ES2015-style shorthand table initialization
String interpolation
Functions declared in expressions can be named now (local foo = function foo() {})
Named bindings declaration (‘let’)
Support call()/acall() delegates for classes
min(), max(), clamp() global functions added to base library
string default delegates: .subst(), .replace(), .join(), .split(), .concat() methods added
table default delegates: .map(), .each(), .findindex(), .findvalue(), .reduce(), __merge(), .__update() methods added
array default delegates: .each(), .findvalue(), .replace() methods added
Support negative indexes in array.slice()
Class methods hinting (that can gives performance of LuaJIT in nonJIT mode)
Compiler directives for stricter and thus safer language (some of them can be used to test upcoming or planned language changes)
Added C APIs not using stack pushes/pops
Variable change tracking
Function ‘freeze()’ for instances, tables, arrays. Make object immutable. Can be checked with ‘is_frozen’ method
Removed features
Support for comma operator removed (were never used, but were error-prone, like table = {[“foo”, “bar”] = null} instead of [[“foo”,”bar”] = null])
Class and member attributes removed (were never used in any real code)
Adding table/class methods with class::method syntaxic sugar disallowed (as There should be one – and preferably only one – obvious way to do it.)
# single line comments removed (as There should be one – and preferably only one – obvious way to do it.)
Support for post-initializer syntax removed (was ambiguous, especially because of optional comma)
Removed support for octal numbers (error-prone)
Changes
Functions and classes are locally scoped
Referencing the closure environment object (‘this’) is explicit
There is no fallback to global root table for undeclared variables, need to use :: operator now
Constants and enums are now locally scoped by default
‘global’ keyword for declaring global constants and enum explicitly
Arrays/strings .find() default delegate renamed to .indexof()
getinfos() renamed to getfuncinfos() and now can be applied to callable objects (instances, tables)
array.append() can take multiple arguments
changed arguments order for array.filter() to unify with other functions
syntax for type methods call (for tables) (table.$rawdelete(“rawdelete”) will work for table {rawdelete=@() null})
compiler is now AST based with some optimizations (like closure hoisting) and checks. Analyzer works on the same AST.
Use Python style for extends (let Baz = class(Bar) //(instead of Baz = class extends Bar)
Remove ‘delete’ operator (use table.rawdelete() or table.$rawdelete() instead). Optional behavior specified with pragma #forbid-delete-operator #allow-delete-operator
lots of methods moved to standard library from global namespaces
setroottable() removed. Can be done with 2 lines of code (let root=getroottable(); root.each(@(_, k) root.rawdelete(k)); root.__update(newroot))
setconsttable() removed. It can break things. The only safe way to use it - to set const tables before for script evaluation (which can be done for compilestring()).
Possible future changes
See RFCs page