Edit on GitHub


This is a draft for features that are not implemented yet. Once a feature here is completed, its associated text will be moved into the overview page.

Don’t expect any of the examples here to work or be implemented in the future exactly as presented here, these are mostly ideas.

Iterated For

local a = {'a', 'b', 'c'}
for i,v in ipairs(a) do
  print(i, v) -- outputs 1 a 2 b 3 c

Iterators are useful to create more complex for loops:

local function multiples_countdown(s, e)
  return function(e, i)
      i = i - 1
      if i < e then return nil end
    until i % 2 == 0
    return i
  end, e, s+2

for i,b in multiples_countdown(10, 0) do
  print(i) -- outputs 10 8 6 4 2 0

Records as tuples

Records can also be used as tuples:

local a: record{integer, integer}
a = {1,2}
a[1] = 0


Union can store multiple types at the same block of memory:

local u: union{integer,string} -- variable of type union, initialized to its first type 'integer'
print(u) -- outputs 0
u = 'string' -- u now holds a string
print(u) -- outputs 'string'

local u: union(uint16){integer,string} -- union that can hold more runtime types
local u: union(void){integer,string} -- union that holds all types at the same time (unsafe)

Unions are slightly different from C union by default, because it has an uint8 internally that holds the current type at runtime, thus the union size will have at least the size of the largest type plus the size of uint8. By default unions cannot hold more than 256 different types. The internal type


Tables are just like Lua tables:

local t1 = {} -- empty table
local t2: table -- empty table
local t3 = {x = 1, y = 2} -- simple table
local t4 = {1 , 2} -- simple table
local t5 = {a = 1, [2] = "a", 1} -- complex table

Tables triggers usage of the garbage collector.


Optional type is actually a union of a niltype and any other type, it is used to declare a variable that may hold or not a variable:

local a: union{niltype,string} -- variable that may hold a string, initialized to 'nil'
assert(a == nil)
assert(not a)
print(a) -- outputs 'nil'
a = 'hi'
print(a) -- outputs 'hi'

-- syntax sugar for union union{niltype,string}
local v: string?

Optional types are useful for passing or returning variables that maybe set or not:

local function foo(a: integer?): integer?
  if not a then
    return nil
  return a + 1

local a = inc(1)
print(a) -- outputs '1'
local b = inc(nil)
print(b) -- outputs 'nil'


Closure are functions declared inside another function that captures variables from the upper scope, by default they capture values by shared references using the garbage collector, this choice was made to make Nelua code compatible with lua semantics:

local function main()
  local a = 1 -- a is promoted to a heap variable internally because it's captured by a closure
  local function foo()
    -- captured 'a' garbage collected reference
    a = 2
main()  -- outputs 2

To make the above possible the compiler promote any captured variable to heap variables and adds references of them to the garbage collector, however we can explicitly specify to capture the variable by its stack reference:

-- capture all value by garbage collected copies
local function main()
  local a = 1
  local function foo() <byref>
    -- captured 'a' by stack reference
    a = 2
  print(a) -- outputs 2

The advantage of capturing by its stack reference is that the closure becomes much more lightweight because we don’t need to promote to heap variables or use the garbage collector, but the disadvantage is that the function can not be called outside is parent scope, making this more unsafe and is responsibility of the programmer to make sure this doesn’t happen otherwise would cause an undefined behavior and potentially a crash.

Variable arguments

Variable arguments functions can be implemented as poly functions, the syntax is like in Lua using the ..., and can be used to forward to another variable argument function:

local function print_proxy(a, ...)
  print(a, ...)
print_proxy(1,2,3) -- outputs 1 2 3

On each call a different types call a real function will be implemented.

The arguments can be accessed individually using the select builtin directive (like in Lua):

local function print_first_two(...)
  local a = select(1, ...)
  local b = select(2, ...)
  local n = select('#', ...)
  print(a, b, n)
print_first_two('a','b') -- outputs "a b 2"

It can be combined with multiple return functions:

local function get_two()
  return 1, 2
local function print_all(...)
print_all(get_two()) -- outputs "1 2"


Static Modules

Modules are useful to separate code scopes using local variables to avoid type and function name clashing across the code base.

Creating module hello:

-- mymodule.lua
local mymodule = @record{}

local a = 1 -- private variable
local function get_a() -- private function
  return a

global mymodule.b = 2 -- variable exported to the module
function mymodule.foo() -- function exported to the module
  return get_a()

return mymodule

Using the module:

local mymodule = require 'mymodule'