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 ...
'...' or "...""""...""" or '''...'''{{...}}"value is {{x}}" instead of "value is " + x{{...}}// 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}}.
"""
Use inline string templates instead. The template() function has a rare and specific purpose.
Prefer short names: 1-2 letters when reasonable (i, j, x, y, z, n, s, h, etc.)
When comparing: use a, b
When more letters are needed:
pwd for password, ts for timestamp, h for hashuser, req, msg, data, itemuser not doc or documentmy_doc, my_input, my_var_private, _internal// for single-line, /* ... */ for multi-linex = x + 1 // increment x// 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.
*/
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
set(x, y, relative = true) over set(x, y, nil, nil, true)// 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)
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
count = 0
while count < 5 do
print(count)
count = count + 1
end
if age >= 18 then
print("Adult")
elseif age >= 13 then
print("Teenager")
else
print("Child")
end
status = age >= 18 ? "adult" : "minor"
function greet(name)
return "Hello, {{name}}"
end
// Or assign to variable
double = function(x)
return x * 2
end
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)
// 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
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
// 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()
// 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)
.du extensionfetch_user.du, hash_password.du, string_utils.du- NOT _.mdtry
data = load("config.json")
catch (e)
print("Failed to load: {{e}}")
end
function validate(age)
if age < 0 then
throw("Age cannot be negative")
end
return age
end
end keyword instead{{expr}} in any string() to create copiesvar to explicitly create locals, assignments look up scope chainuser not my_user, h not my_hash"Hello {{name}}" not "Hello " + name