Duso Code Style Guide

Indentation

Strings

Strings allow for UTF-8 in Duso. Most other values will coerce cleanly to strings without an explicit tostring(). You may concat strings with + NOT . or ...

Single vs Multi-line

String Templates

String Template Examples

// Single-line with template
x = 10
s = "x equals {{x}}"

// Ternary in template
status = "Status: {{alive ? 'alive' : 'dead'}}"

// Function call in template
greeting = "Welcome {{get_name()}}"

// Multi-line with template
msg = """
  Hello {{name}},
  Your score is {{score}}.
"""

Do Not Use template() Builtin

Use inline string templates instead. The template() function has a rare and specific purpose.

Variables

Naming

Length and Context

Avoid

Comments

Style

Guidelines

Examples

// Good
h = hash_password(pwd)
ts = now()

// Bad
x = x + 1  // increment x

// Switch to multi-line for multiple comments
/*
  Fetch user by ID, validate permissions,
  then update their profile in the database.
  Returns nil if validation fails.
*/

Function Arguments

Duso supports positional and named arguments, and a call may mix them. Put every positional argument first, then every named one — f(1, 2, c = 3), never f(a = 1, 2, 3).

The language does not enforce this. Positional arguments fill parameter slots left to right no matter where they sit in the call, and named arguments are applied over the top, so a named argument placed early does not reserve its slot:

function f(a, b, c)
  return "a={{a}} b={{b}} c={{c}}"
end

f(1, 2, 3)       // a=1 b=2 c=3
f(1, b = 2, c = 3)   // a=1 b=2 c=3
f(a = 1, 2, 3)   // a=1 b=3 c=nil  <- silently wrong, no error

Named Arguments

Examples

// Good: named args skip unused positionals
result = api_call(url, method = "POST", timeout = 30)

// Avoid: positional args with nils for skipped params
result = api_call(url, "POST", nil, nil, 30)

Loops and Control Flow

For Loops

Use for...do...end syntax. Two forms:

// Numeric range (inclusive)
for i = 1, 10 do
  print(i)
end

// Iterate over array
for item in items do
  print(item)
end

While Loops

count = 0
while count < 5 do
  print(count)
  count = count + 1
end

If/Else

if age >= 18 then
  print("Adult")
elseif age >= 13 then
  print("Teenager")
else
  print("Child")
end

Ternary for Simple Conditions

status = age >= 18 ? "adult" : "minor"

Functions

Definition

function greet(name)
  return "Hello, {{name}}"
end

// Or assign to variable
double = function(x)
  return x * 2
end

Higher-Order Functions

When passing function literals inside another function, indent them to make it clear at a glance what’s happening. See examples.

// Map: transform each element
squared = map(nums, function(x)
  return x * x
end)

// Filter: keep matching elements
evens = filter(nums, function(x)
  return x % 2 == 0
end)

// Reduce: combine to single value
sum = reduce(nums, function(acc, x)
  return acc + x
end, 0)

Objects and Arrays

Objects (Key-Value Maps)

// Define
person = {
  name = "Alice",
  age = 30,
  city = "Portland"
}

// Preferred Access
print(person.name)

// secondary access (useful for variable keys or illegal keys)
field = "name"
print(person[field])
print(req["Content-Type"])

// Modify
person.age = 31

Arrays (Ordered Lists)

nums = [10, 20, 30]

// 0-indexed
print(nums[0])

// Length
print(len(nums))

// Add to end
push(nums, 40)

// Iterate
for n in nums do
  print(n)
end

Objects with Methods

// Object with functions as methods
agent = {
  name = "Alice",
  age = 30,
  greet = function(msg)
    return "{{msg}}, I am {{name}} (age {{age}})"
  end,
  birthday = function()
    age = age + 1
  end
}

// Call methods
print(agent.greet("Hello"))
agent.birthday()

Objects as Blueprints/Constructors

// Blueprint
config = {timeout = 30, retries = 3}

// Create copy with defaults
c1 = config()

// Override specific fields
c2 = config(timeout = 60)

// Counter "class" pattern
counter = {
  count = 0,
  increment = function()
    count = count + 1
  end,
  value = function()
    return count
  end
}

// Create independent instances
counter1 = counter()
counter2 = counter()

counter1.increment()
print(counter1.value())  // 1
print(counter2.value())  // 0 (independent)

Duso Script File Naming

Markdown File Names

Error Handling

Try/Catch

try
  data = load("config.json")
catch (e)
  print("Failed to load: {{e}}")
end

Throw Errors

function validate(age)
  if age < 0 then
    throw("Age cannot be negative")
  end
  return age
end

Summary of Key Differences from Lua/JavaScript

General Principles

  1. Prefer short, context-aware names - user not my_user, h not my_hash
  2. Use string templates over concatenation - "Hello {{name}}" not "Hello " + name
  3. Keep functions small and focused - one responsibility
  4. Use named arguments for clarity - especially with 3+ parameters
  5. Comment the why, not the what - code should be self-documenting
  6. Indent consistently with 2 spaces - no tabs, ever