Differences from Lua

Key differences between Behl and Lua for developers familiar with Lua.

Table of contents

  1. Overview
  2. Syntax Differences
    1. Statement Terminators
    2. Blocks and Scope
    3. Comments
    4. Variable Declaration
    5. Functions
    6. String Concatenation
    7. Logical Operators
    8. Comparison Operators
    9. Elseif vs elseif
  3. Table Indexing
    1. 0-Indexed vs 1-Indexed
    2. For Loops
    3. Iteration
  4. Operators
    1. Power Operator
    2. Bitwise Operators
  5. Type System
    1. Type Names
    2. Type Checking
  6. Modules and Imports
    1. Module System
  7. Functions
    1. Multiple Return Values
    2. Varargs
  8. Global Variables
    1. Assignment
    2. Table Construction
  9. Standard Library
    1. Common Differences
    2. Missing Features
  10. Metatables
    1. Metamethods
  11. Error Handling
    1. Raising Errors
    2. Protected Calls
  12. C API
    1. Comparison
  13. Performance
  14. Migration Checklist
  15. Summary

Overview

Behl is inspired by Lua’s semantics but uses C-like syntax. If you’re familiar with Lua, this guide will help you understand the key differences.


Syntax Differences

Statement Terminators

Lua:

local x = 10
print(x)

behl:

let x = 10
print(x)

Semicolons ; are optional in Behl (automatic semicolon insertion like JavaScript).

Blocks and Scope

Lua:

if condition then
    -- code
end

while condition do
    -- code
end

for i = 1, 10 do
    -- code
end

behl:

if (condition) {
    // code
}

while (condition) {
    // code
}

for (let i = 0; i < 10; i++) {
    // code
}

Behl uses {} braces for blocks instead of do...end or then...end.

Comments

Lua:

-- Single line comment
--[[ Multi-line
     comment ]]

behl:

// Single line comment
/* Multi-line
   comment */

Variable Declaration

Lua:

local x = 10

behl:

let x = 10;
const PI = 3.14;  // Immutable

Behl requires explicit let or const keywords.

Functions

Lua:

function add(a, b)
    return a + b
end

local multiply = function(a, b)
    return a * b
end

behl:

function add(a, b) {
    return a + b;
}

let multiply = function(a, b) {
    return a * b;
};

String Concatenation

Lua:

local s = "Hello" .. " " .. "World"
local msg = "Count: " .. tostring(42)

behl:

let s = "Hello" + " " + "World";
let msg = "Count: " + tostring(42);

Behl uses + instead of .. for concatenation.

Logical Operators

Lua:

if a and b then end
if a or b then end
if not a then end

behl:

if (a && b) {}
if (a || b) {}
if (!a) {}

Behl uses C-style logical operators.

Comparison Operators

Lua:

if a ~= b then end  -- Not equal

behl:

if (a != b) {}  // Not equal

Elseif vs elseif

Lua:

if condition1 then
    -- code
elseif condition2 then
    -- code
else
    -- code
end

behl:

if (condition1) {
    // code
} elseif (condition2) {
    // code
} else {
    // code
}

Behl uses elseif (one word, like Lua), but with C-like syntax.


Table Indexing

0-Indexed vs 1-Indexed

CRITICAL DIFFERENCE: behl tables are 0-indexed, Lua tables are 1-indexed.

Lua:

local t = {10, 20, 30}
print(t[1])  -- 10
print(t[3])  -- 30

behl:

let t = {10, 20, 30};
print(t[0]);  // 10
print(t[2]);  // 30

For Loops

Lua:

for i = 1, 10 do
    print(i)  -- 1, 2, 3, ..., 10
end

behl:

for (let i = 0; i < 10; i++) {
    print(i);  // 0, 1, 2, ..., 9
}

Iteration

Lua:

for k, v in pairs(t) do
    print(k, v)
end

Behl:

for (k, v in pairs(t)) {
    print(k + ": " + tostring(v));
}

Note the parentheses around the iterator expression and variables in Behl.


Operators

Power Operator

Lua:

local x = 2 ^ 8  -- 256

behl:

let x = 2 ** 8;  // 256

Behl uses ** for exponentiation (like Python).

Bitwise Operators

Lua 5.3+:

local a = x & y   -- AND
local b = x | y   -- OR
local c = x ~ y   -- XOR
local d = ~x      -- NOT
local e = x << 1  -- Left shift
local f = x >> 1  -- Right shift

Behl:

let a = x & y;    // AND
let b = x | y;    // OR
let c = x ^ y;    // XOR (Behl uses ^ instead of ~)
let d = ~x;       // NOT
let e = x << 2;   // Left shift
let f = x >> 2;   // Right shift

Note: In Behl, ^ is XOR (not power). Power is **.


Type System

Type Names

Both languages have similar types, but with minor name differences:

Lua behl
nil nil
boolean boolean
number integer or number
string string
function function
table table
userdata userdata

Key difference: Behl distinguishes between integer (int64) and number (double), whereas Lua 5.3+ has integer and float subtypes of number.

Type Checking

Lua:

local t = type(x)
if t == "number" then
    -- ...
end

behl:

let t = typeof(x);
if (t == "integer" || t == "number") {
    // ...
}

Behl uses typeof() instead of type().


Modules and Imports

Module System

Lua:

local math = require("math")
print(math.pi)
print(math.sqrt(16))

behl:

const math = import("math");
print(math.PI);
print(math.sqrt(16));
  • Behl uses import() instead of require()
  • Behl supports both dot notation (.) and bracket notation ([]) for table access

Functions

Multiple Return Values

Both support multiple returns, but syntax differs:

Lua:

function divmod(a, b)
    return a / b, a % b
end

local q, r = divmod(10, 3)

behl:

function divmod(a, b) {
    return a / b, a % b;
}

let q, r = divmod(10, 3);

Varargs

Lua:

function sum(...)
    local args = {...}
    local total = 0
    for _, v in ipairs(args) do
        total = total + v
    end
    return total
end

Behl:

function sum(...) {
    let total = 0;
    for (let i = 0; i < rawlen(...); i++) {
        total = total + (...)[i];
    }
    return total;
}

sum(1, 2, 3, 4);

Behl fully supports varargs with similar semantics. See Varargs for details.


Global Variables

Assignment

Lua:

x = 10  -- Global (no 'local')

behl:

let x = 10;  // Must use 'let' or 'const'

Behl requires explicit variable declarations. There is no implicit global assignment.

Table Construction

Lua:

local t = {name = "Alice", age = 30}
print(t.name)

behl:

let t = { name = "Alice", age = 30 };
print(t.name);  // Or t["name"]

Behl supports both key = value shorthand (for identifiers) and ["key"] = value (for any expression).


Standard Library

Common Differences

Lua Behl Notes
type() typeof() Type introspection
#t rawlen(t) Table length
t[#t+1] t[rawlen(t)] Append (0-indexed)
math.pi math.PI Constants in uppercase
string.len(s) string.len(s) Dot notation supported

Missing Features

Behl currently does not support:

  • ... (varargs)
  • select()
  • ipairs() (use pairs() instead, remember 0-indexing)
  • Lua 5.4+ attributes like <const> and <close>
  • Coroutines (coroutine library)
  • Weak tables

Metatables

Metamethods

Behl supports metatables with similar metamethods to Lua:

Lua:

local mt = {
    __tostring = function(t)
        return "MyTable"
    end,
    __add = function(a, b)
        return a.value + b.value
    end
}
setmetatable(t, mt)

behl:

let mt = {
    ["__tostring"] = function(t) {
        return "MyTable";
    },
    ["__add"] = function(a, b) {
        return a["value"] + b["value"];
    }
};
setmetatable(t, mt);

Supported metamethods:

  • Arithmetic: __add, __sub, __mul, __div, __mod, __pow, __unm
  • Bitwise: __band, __bor, __bxor, __bnot, __shl, __shr
  • Comparison: __eq, __lt, __le
  • Table: __index, __newindex, __len, __pairs
  • Other: __call, __tostring, __gc

Error Handling

Raising Errors

Lua:

error("Something went wrong")

behl:

error("Something went wrong");

Same function name and behavior.

Protected Calls

Lua:

local success, result = pcall(risky_function)
if not success then
    print("Error: " .. result)
end

behl:

let success, result = pcall(risky_function);
if (!success) {
    print("Error: " + result);
}

Similar behavior, different syntax.


C API

Comparison

Both have similar C/C++ APIs for embedding:

Lua C API:

lua_State* L = luaL_newstate();
lua_pushinteger(L, 42);
lua_setglobal(L, "answer");
lua_close(L);

behl C++ API:

behl::State* S = behl::new_state();
behl::push_integer(S, 42);
behl::set_global(S, "answer");
behl::close(S);

The behl API is designed to be familiar to Lua developers while leveraging C++20 features internally.


Performance

Behl aims to be competitive with Lua:

  • Similar register-based VM architecture
  • Incremental garbage collection
  • Competitive performance in many benchmarks

Migration Checklist

When porting Lua code to behl:

  • Change -- comments to // or /* */
  • Replace then...end / do...end with {...}
  • Change local to let or const
  • Replace .. concatenation with +
  • Replace and, or, not with &&, ||, !
  • Replace ~= with !=
  • Change ^ (power) to **
  • Change bitwise XOR from ~ to ^
  • Adjust all array indices from 1-based to 0-based
  • Change type() to typeof()
  • Change require() to import()

Summary

Behl keeps Lua’s powerful semantics (dynamic typing, first-class functions, metatables, GC) while adopting C-style syntax for familiarity. The biggest gotcha is 0-indexed tables - everything else is mostly syntactic sugar.


Copyright © 2025 behl Project. Distributed under MIT License.

This site uses Just the Docs, a documentation theme for Jekyll.