nenu-lang / operators-and-methods
Stable

Operators And Built-In Methods

  • Operators combine compatible typed values; they do not silently convert unrelated types.
  • Array and map closures use the implicit it binding.
  • Primitive methods are fixed built-ins on string, number, and time receivers.

Expression Forms

FormExampleResult
Pathexpense.amountThe type of the referenced binding or field.
CallsplitAmount(total, people)The function return type.
Method calltitle.trim()The method return type.
Indexexpenses[0]The optional collection element type.
Ternarysettled : "Settled" | "Open"One of two compatible result types.
Array literal[first, second]A compatible element array.
Map literal{ kitchen: total }A string-keyed value map.
Object literalExpense { ... }The named entity or type.
Absent value?Absence for an optional context.

Ternary Expressions

code
1string label = expense.status == ExpenseStatus.Settled : "Settled" | "Open"

The form is condition : then_value | else_value. The condition must be boolean, both branches must be type-compatible, and Nenu allows no more than two nested ternary levels. Ternary expressions have lower precedence than the ordinary logical and arithmetic operators that form their condition and results.

Arithmetic And Concatenation

OperatorMeaningExample
+Numeric addition, string concatenation, or compatible array concatenation.amount + fee
-Numeric subtraction.paid - owed
*Numeric multiplication.share * people
/Numeric division.amount / people
%Numeric remainder.count % 2
Unary -Numeric negation.-balance
code
1number each = expense.amount / member_count2number remainder = expense.amount % member_count3string label = expense.title + " expense"4Expense[] next = expenses + [expense]

Nenu type-checks the operands. Unary minus on bool or ?, numeric arithmetic on strings, and concatenation of incompatible array element types are errors.

Comparison And Logic

OperatorsPurpose
==, !=Equality and inequality for compatible values.
>, <, >=, <=Ordering comparisons for compatible ordered values.
and, orCombine boolean expressions.
!Negate a boolean expression.
??Use the left value when present, otherwise the fallback.
code
1bool expensive = expense.amount >= 1002bool visible = expense.status != ExpenseStatus.Draft and !hidden3string note = expense.note ?? "No note"

Collection Access And Emptiness

code
1Expense? first_expense = expenses[0]2number? kitchen_total = totals["kitchen"]3number expense_count = expenses.length4number room_count = totals.len56if expenses.empty {7  return "No expenses"8}

Use a numeric index for an array and a string key for a map. Arrays, maps, and strings expose the equivalent numeric properties .length and .len; do not add parentheses. Arrays and maps also expose .empty. Normal indexing returns an optional value because the position or key may be missing; narrow it with with or supply a compatible fallback with ??.

Array Methods

MethodResultPurpose
filter(condition)T[]Keep items for which the condition is true.
first(condition)T?Return the first matching item or absence.
last(condition)T?Return the last matching item or absence.
collect(expression)U[]Project each item to a new array value.
any(condition)boolTest whether at least one item matches.
all(condition)boolTest whether every item matches.
push(item)Mutates T[]Append one compatible item.
code
1open = expenses.filter(it.status == ExpenseStatus.Open)2largest = expenses.first(it.amount > 1000)3titles = expenses.collect(it.title)4has_drafts = expenses.any(it.status == ExpenseStatus.Draft)5all_positive = expenses.all(it.amount > 0)6expenses.push(new_expense)

it is the implicit current item inside the array-method expression. push requires parentheses and a value compatible with the array element type.

Map Methods

MethodResult<code>it</code> means
entries()T{}Used as map loop passthrough.
keys()string[]No closure binding.
values()T[]No closure binding.
filterKeys(condition)T{}The string key.
filterValues(condition)T{}The map value.
code
1member_ids = balances.keys()2amounts = balances.values()3active = balances.filterValues(it != 0)4public_balances = balances.filterKeys(it != "internal")56loop balances.entries() as member_id, balance {7  // member_id is string; balance is number.8}

String Methods

MethodResult
trim()Remove surrounding whitespace.
lowercase()Return a lowercase string.
uppercase()Return an uppercase string.
contains(needle)Test whether the string contains text.
startsWith(prefix)Test the beginning of the string.
endsWith(suffix)Test the end of the string.
split(separator)Return string[].
replace(old, new)Return a replaced string.
slice(start, end)Return a string slice.
code
1clean = draft_title.trim()2searchable = clean.lowercase()3is_food = searchable.contains("groceries")4parts = clean.split(" ")

Number And Time Methods

ReceiverMethods
numberabs(), round(), floor(), ceil(), sign()
numberpow(n), sqrt(), log(), log(base)
numbermin(n), max(n), clamp(min, max)
timetoMillis(), addSeconds(n), diffSeconds(other)
code
1rounded = expense.amount.round()2safe_percent = percent.clamp(0, 100)3next_check = expense.createdAt.addSeconds(3600)4age_seconds = next_check.diffSeconds(expense.createdAt)

Standalone Built-In Functions

code
1time current = time.now()2string generated = nanoid()3string short_id = nanoid(12)
CallReturnArguments
time.now()timeNo arguments.
nanoid()stringNo arguments; uses the default identifier length.
nanoid(length)stringOne number length argument.

Built-In Methods And Entity Methods

Built-in methods belong to the resolved receiver type. An entity does not inherit methods from its fields. A custom entity method name is rejected only when the receiver itself already has a built-in method with that name.

code
1fn filter of Expense {2  return self3}

The second declaration is a small isolated example from an Item entity whose tags field is an array. It collides because arrays already provide filter. This rule is based on the receiver type, not on a global blacklist of method names.

Common Mistakes

WrongCorrect
items.push itemitems.push(item)
title.toLowerCase()title.lowercase()
array.length()array.length, array.len, or array.empty
Use array it outside a closureUse the explicit local or loop binding.
Invent time.month()Use only the documented time methods.

Continue Learning