Types and Values

Table of contents

  1. Overview
  2. Basic Types
  3. Type Query
  4. Nil
  5. Booleans
  6. Numbers
    1. Integer Literals
    2. Floating-Point Literals
    3. Type Promotion
    4. Number Precision
    5. Integer Overflow
  7. Strings
    1. String Literals
    2. Escape Sequences
    3. String Concatenation
    4. String Length
    5. String Operations
  8. Functions
  9. Tables
  10. Userdata
    1. Characteristics
    2. Usage from Scripts
    3. Features
    4. Creating Userdata
  11. Type Conversions
    1. Explicit Conversions
    2. Implicit Conversions

Overview

Behl is dynamically typed. Values carry type information at runtime, not variables.

let x = 42;        // x holds an integer
x = "hello";       // now x holds a string
x = {1, 2, 3};     // now x holds a table

Basic Types

Type Description Example
nil Absence of value nil
boolean True or false true, false
integer 64-bit signed integer 42, 0xFF, -10
number 64-bit floating point 3.14, 1.5e-10
string Immutable text "hello", 'world'
function Callable function Functions and closures
table Associative array {1, 2, 3}
userdata C++ objects Managed from C++ API

Type Query

Use typeof() to inspect a value’s type:

let x = 42;
print(typeof(x)); // "integer"

let y = 3.14;
print(typeof(y)); // "number"

let s = "hello";
print(typeof(s)); // "string"

Nil

nil represents the absence of a value:

let x = nil;
if (x == nil) {
    print("x is nil");
}

// Accessing non-existent table keys returns nil
let t = {};
print(t.missing); // nil

Booleans

Boolean values are true and false:

let isTrue = true;
let isFalse = false;

// Truthiness: Only false and nil are falsy
// Everything else is truthy (including 0 and empty strings)
if (0) {
    print("0 is truthy!"); // This prints
}

if ("") {
    print("Empty string is truthy!"); // This also prints
}

if (false) {
    print("Won't print");
}

if (nil) {
    print("Won't print");
}

Numbers

Behl distinguishes between integers and floating-point numbers:

Integer Literals

let dec = 42;      // Decimal
let hex = 0xFF;    // Hexadecimal (255)
let neg = -10;     // Negative

// Hexadecimal (case insensitive)
let a = 0xff;      // 255
let b = 0xFF;      // 255
let c = 0XFF;      // 255
let d = 0xAbCdEf;  // 11259375

// Leading zeros are ignored (NOT octal)
let e = 007;       // 7 (decimal, not octal)
let f = 0123;      // 123 (decimal, not octal)

Note: Unlike C, leading zeros do NOT indicate octal. 007 is decimal 7, not octal 7.

Floating-Point Literals

let f1 = 3.14;
let f2 = 1.5e-10;  // Scientific notation
let f3 = .5;       // 0.5
let f4 = 5.;       // 5.0

Type Promotion

Arithmetic operations promote to floating-point when needed:

let x = 10 / 3;    // 3.333... (number)
let y = 10 / 2;    // 5 (integer - exact division)
let z = 5 + 3.14;  // 8.14 (promoted to number)

Number Precision

  • Integers: 64-bit signed (-2^63 to 2^63-1)
  • Floats: IEEE 754 double precision (64-bit)

Integer Overflow

Integer arithmetic uses wrapping (two’s complement) on overflow:

let max = 9223372036854775807  // INT64_MAX
let overflowed = max + 1        // Wraps to INT64_MIN (-9223372036854775808)

let min = -9223372036854775808  // INT64_MIN  
let underflowed = min - 1       // Wraps to INT64_MAX (9223372036854775807)

// Multiplication overflow
let large = 9223372036854775807
let result = large * 2          // Wraps to -2

Note: Overflow does not cause errors or convert to floats - values wrap around silently.

Strings

Strings are immutable sequences of characters:

String Literals

let s1 = "double quotes";
let s2 = 'single quotes';

// Both styles are equivalent
let same1 = "hello";
let same2 = 'hello';
print(same1 == same2); // true

Escape Sequences

Sequence Meaning
\a Bell/Alert (ASCII 7)
\b Backspace (ASCII 8)
\f Form feed (ASCII 12)
\n Newline (ASCII 10)
\r Carriage return (ASCII 13)
\t Horizontal tab (ASCII 9)
\v Vertical tab (ASCII 11)
\\ Backslash
\" Double quote
\' Single quote
\<newline> Escaped newline (ignored, allows multi-line literals)
let multiline = "Line 1\nLine 2\nLine 3";
let tabs = "Column1\tColumn2\tColumn3";
let quoted = "She said \"Hello!\"";

// Escaped newline allows breaking long strings
let long_str = "This is a very \
long string that spans \
multiple lines in source code";

String Concatenation

Use the + operator to concatenate strings:

let greeting = "Hello, " + "World!";
let msg = "Count: " + tostring(42);  // Convert numbers to strings

// Chain multiple concatenations
let full = "First " + "Second " + "Third";

Note: Automatic coercion is not supported. Use tostring() to convert numbers:

let x = "Value: " + 42;          // Error!
let x = "Value: " + tostring(42); // OK

String Length

Use the # operator (via rawlen) or string.len():

const string = import("string");

let s = "hello";
print(rawlen(s));        // 5
print(string.len(s));    // 5

String Operations

See Standard Library - string module for string manipulation functions:

const string = import("string");

string.upper("hello");      // "HELLO"
string.sub("hello", 0, 2);  // "hel"
string.find("hello", "ll"); // 2

Functions

Functions are first-class values:

function greet(name) {
    return "Hello, " + name;
}

// Functions are values
let fn = greet;
print(typeof(fn)); // "function"

See Functions for complete documentation.

Tables

Tables are associative arrays that can serve as arrays, dictionaries, or objects:

let arr = {10, 20, 30};     // Array-like
let dict = {key = 42};  // Dictionary-like

print(typeof(arr));  // "table"
print(typeof(dict)); // "table"

See Tables for complete documentation.

Userdata

Userdata represents opaque C++ objects exposed to Behl scripts through the C++ API. They are used to wrap native resources like file handles, network sockets, or custom data structures.

Characteristics

  • Opaque: Scripts cannot directly access userdata fields
  • Type-safe: Each userdata has a unique identifier (UID) to prevent type confusion
  • Garbage collected: Automatically freed when no longer referenced
  • Metatable support: Can have metatables for custom behavior
  • Finalizers: __gc metamethod called before collection

Usage from Scripts

// Created from C++ API
let file = os.open("data.txt", "r");
print(typeof(file));  // "userdata"

// Access through C++ functions
let line = file_read(file);

// Type checking
if (typeof(file) == "userdata") {
    // It's userdata, but we don't know which type
}

Features

Metatables: Userdata can have metatables for custom operators and methods:

let v1 = vec2_new(1.0, 2.0);
let v2 = vec2_new(3.0, 4.0);
let v3 = v1 + v2;  // Calls __add metamethod
print(v3);         // Calls __tostring

Automatic cleanup: Userdata with __gc metamethods are automatically finalized:

function process_file() {
    let f = file_open("data.txt", "r");
    // ... use file ...
    // File automatically closed by GC even if we forget
}

Type safety: The C++ API enforces type checking:

let table = {};
file_read(table);  // TypeError: bad argument #1 (expected userdata, got table)

let file1 = file_open("a.txt", "r");
let vec = vec2_new(1.0, 2.0);
file_read(vec);    // TypeError: userdata type mismatch

Creating Userdata

See Userdata for details on creating and managing userdata types from C++.

Common use cases:

  • File I/O handles
  • Database connections
  • Graphics resources (textures, shaders)
  • Network sockets
  • Complex data structures (trees, graphs)
  • Native library bindings

Type Conversions

Explicit Conversions

Function Description
tonumber(x) Convert to number, returns nil on failure
tostring(x) Convert to string
let n = tonumber("42");     // 42
let s = tostring(123);      // "123"
let bad = tonumber("xyz");  // nil

Implicit Conversions

Behl has minimal implicit conversion:

  • Arithmetic: Integer + Float → Float
  • Comparison: Same-type comparison only
  • Strings: No automatic number coercion
let x = 5 + 3.14;         // OK: 8.14 (promoted to float)
let s = "Value: " + 42;   // Error: no auto conversion
let ok = "Value: " + tostring(42); // OK: "Value: 42"

Copyright © 2025 behl Project. Distributed under MIT License.

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