# Getting Started with Soplang
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Welcome to Soplang 3! This guide walks you through installing Soplang, writing your first program, and the core concepts you will use every day.
1. Installation [#1-installation]
Download a prebuilt release for your platform from the [downloads page](/downloads), or build it from source with Cargo. Then check that it works:
```bash
soplang --version
```
For all options (installers, Docker, building from source), see the [installation guide](/docs/00_installation).
2. Your First Soplang Program [#2-your-first-soplang-program]
Create a file named `hello.sop`:
Running Your Program [#running-your-program]
Open a terminal in the folder where you saved the file and run:
```bash
soplang hello.sop
```
You should see:
```bash
Salaan, Adduunka!
Ku soo dhowow Soplang 3!
Salaan, Developer!
```
Congratulations, you just wrote and ran your first Soplang program. You can also experiment interactively by running `soplang isdhexgal` to open the REPL. Bare `soplang` opens a command browser in a terminal. See [CLI & REPL](/docs/19_cli-and-repl).
3. Basic Concepts [#3-basic-concepts]
Variables and Data Types [#variables-and-data-types]
Soplang supports both dynamic and static typing. Use `door` for a dynamic variable, or a type keyword (`abn`, `jajab`, `qoraal`, `bool`, `teed`, `walax`) to fix the variable's type.
Control Flow [#control-flow]
Code blocks are wrapped in curly braces `{}` and conditions go in parentheses `()`. Indentation is only for readability.
0) {
qor(tirin)
tirin = tirin - 1
}
qor("Duul!")`}
/>
Functions [#functions]
Functions are defined with `hawl` and return values with `celi`. Parameters and the return value can optionally be typed.
Next Steps [#next-steps]
* [Syntax Basics](/docs/01_syntax-basics): comments, blocks, and the rules of the language
* [Variables](/docs/03_variables): `door`, static types, and `madoor` constants
* [Classes](/docs/16_classes): object-oriented programming with `qaab`
* [Error Handling](/docs/17_error-handling): `tijaabi` and `qabo`
* [Keywords Reference](/docs/14_keywords-reference): every keyword in one place
# Installing Soplang 3.6
Installing Soplang 3.6 [#installing-soplang-36]
[Soplang 3.6.0](https://github.com/soplang/soplang/releases/tag/v3.6.0) provides
packages for Linux x86\_64, Windows x64, and macOS Apple Silicon. A Linux amd64
Docker image is also available.
Release packages [#release-packages]
Download your platform's package and the release's combined `SHA256SUMS`.
| Platform | Package | Requirements |
| ------------------- | ---------------------------------------------------------------- | --------------------------- |
| Linux x86\_64 | `soplang_3.6.0_amd64.deb` or `soplang-3.6.0-linux-x86_64.tar.gz` | glibc 2.39 or later; libgcc |
| Windows x64 | `soplang-setup.exe` or `soplang-3.6.0-windows-AMD64.zip` | Windows x64 |
| macOS Apple Silicon | `soplang-3.6.0-macos-arm64.tar.gz` | macOS 15.7.9 or later |
The Windows installer is unsigned and the macOS archive is not notarized.
The release includes archives and a Debian package. The macOS builder may
produce a DMG when `create-dmg` is available.
Verify a download [#verify-a-download]
Keep `SHA256SUMS` beside your downloads. On Linux or macOS, check the selected
file against its entry, or check the full manifest after downloading all assets:
```sh
sha256sum -c SHA256SUMS # Linux
shasum -a 256 -c SHA256SUMS # macOS
```
On Windows, compare `Get-FileHash -Algorithm SHA256` with the matching
line in `SHA256SUMS`.
Linux [#linux]
Install the Debian package:
```sh
sudo dpkg -i soplang_3.6.0_amd64.deb
soplang nooc
```
Or extract the archive:
```sh
tar -xzf soplang-3.6.0-linux-x86_64.tar.gz
./soplang/soplang nooc
```
Keep the archive's executable and `lib/soplang` directory together. Debian
installs the executable at `/usr/bin/soplang` and its runtime files at
`/usr/lib/soplang`.
Windows [#windows]
Run `soplang-setup.exe`. Its optional tasks add Soplang to PATH and associate
`.sop` and `.so` source files. Open a new terminal after installation:
```powershell
soplang nooc
soplang -c 'qor("Salaan!")'
```
Alternatively, extract the ZIP and run `soplang.exe` inside its `soplang`
directory. Keep the `lib` directory beside the executable.
macOS [#macos]
Extract the Apple Silicon archive:
```sh
tar -xzf soplang-3.6.0-macos-arm64.tar.gz
./Soplang.app/Contents/MacOS/soplang nooc
```
This is a command-line application. Keep the complete app bundle and add its
`Contents/MacOS` directory to PATH if desired. Intel Mac packages are not part
of this release; follow the [source build guide](https://github.com/soplang/soplang/blob/v3.6.0/docs/BUILD_GUIDE.md) for other
targets.
Docker [#docker]
```sh
docker run --platform linux/amd64 --rm soplang/soplang:3.6.0 nooc
docker run --platform linux/amd64 --rm -v "$PWD:/scripts:ro" soplang/soplang:3.6.0 program.sop
docker run --platform linux/amd64 --rm -it soplang/soplang:3.6.0 isdhexgal
```
See [Docker usage](https://github.com/soplang/soplang/blob/v3.6.0/docs/docker.md) for writable mounts and building executables.
Run and build programs [#run-and-build-programs]
```sh
soplang fuli program.sop
soplang -c 'qor("Salaan!")'
soplang isdhexgal
soplang dhis program.sop
soplang build program.sop -o program
```
The 3.6 packages include the LLVM and linker components needed for native
builds. Running Soplang and building a program need no separate Rust, Cargo,
Clang, or system linker installation. A built program runs without Soplang or
its source files beside it. It targets the operating system and architecture
of the package that built it. See [installed package details](https://github.com/soplang/soplang/blob/v3.6.0/docs/INSTALLING_PACKAGES.md).
To build the compiler itself, follow the [source build guide](https://github.com/soplang/soplang/blob/v3.6.0/docs/BUILD_GUIDE.md).
For language examples and diagnostics, see the [example catalog](https://github.com/soplang/soplang/blob/v3.6.0/examples/README.md)
and [keyword reference](/docs/14_keywords-reference).
# Soplang Syntax
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Soplang Syntax [#soplang-syntax]
Soplang uses Somali words for familiar programming concepts. This guide introduces the syntax for declarations, functions, control flow, and other language features.
Hello World [#hello-world]
This program uses the built-in `qor()` function to print a message.
**hello-world.sop**
Structure [#structure]
Soplang programs use these building blocks:
* **Declarations** – `door`, `abn`, `jajab`, `qoraal`, `bool`, `teed`, `walax`, and `madoor`
* **Functions** – `hawl` and `celi`
* **Control flow** – `haddii`, `kale`, `dooro`, `kuceli`, and `intay`
* **Classes** – `qaab`, `dhaxal`, `cusub`, and `nafta`
* **Error handling and modules** – `tijaabi`/`qabo` and `keen`
* **Built-ins** – functions such as `qor()`, `gelin()`, and `nooc()`
Curly braces (`{}`) enclose blocks. Statements execute in sequence.
Comments [#comments]
Comments are not executed. Soplang supports single-line comments (`//`) and multiline comments (`/* ... */`).
Basic Rules [#basic-rules]
* **Statement separators:** one statement per line is the usual style. Semicolons (`;`) are optional; `door x = 1; qor(x);` is also valid.
* **Blocks:** `{}` enclose the bodies of conditionals, loops, functions, and classes. Indentation improves readability but does not define blocks.
* **Conditions:** `haddii`, `intay`, and `dooro` require parentheses `()` around their condition or expression.
* **Case sensitivity:** `magac` and `Magac` are different variable names.
* **Strings:** use double quotes (`"..."`) or single quotes (`'...'`). Plain strings preserve backslashes. Use `e"..."` for escapes such as `\n`, or `f"...{name}..."` for interpolation.
* **Concatenation with `+`:** when either operand is a string, the other value is converted to text.
Example Program [#example-program]
This example reads a name and prints a greeting. It combines a function definition, a variable, and built-in functions.
**example.sop**
File Extension [#file-extension]
Soplang source files use the `.sop` extension. Run a file from the command line, or experiment in the interactive REPL.
**run.sh**
```shell
soplang file.sop
```
# Input and Output
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Input and Output in Soplang [#input-and-output-in-soplang]
Soplang provides built-in functions for console output and user input.
qor() – Print to Console [#qor--print-to-console]
Use `qor()` to display a value in the terminal.
**print\_console.sop**
`qor()` accepts **one value**. To print several values together, join them with `+`:
gelin() – Read User Input [#gelin--read-user-input]
Use `gelin()` to read a line of input. The prompt is optional. The result is always a string (`qoraal`).
**read\_input.sop**
Use a conversion function such as `abn()` when you need a number rather than a string.
**type\_conversion.sop**
# Variables
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Soplang Variables [#soplang-variables]
Soplang supports dynamic variables, explicitly typed variables, and constants. The declaration determines whether the variable can change type or be reassigned.
Dynamic Variables – door [#dynamic-variables--door]
Use `door` to declare a dynamically typed variable. Its name is associated with the Somali word *doorsoome* (variable).
**dynamic\_variables.sop**
A variable declared with `door` can hold a value of any type, including a different type after reassignment:
Declare Once [#declare-once]
A name can be declared only once in its scope, including inside a block such as `haddii` or `intay`. To update the value, write `magac = qiime` without repeating `door`.
Static Variables [#static-variables]
Static variables have an explicit type annotation. The compiler and runtime enforce that type on assignments.
Type
Keyword
Stands for
Example
Integer
`abn`
*abyoone*
`abn tirada = 10`
Float
`jajab`
*jajab*
`jajab qiime = 3.14`
String
`qoraal`
*qoraal*
`qoraal magaca = "Soplang"`
Boolean
`bool`
*bool*
`bool sax = run`
List
`teed`
*teed*
`teed liis = [1, 2, 3]`
Object
`walax`
*walax*
`walax qof = {magac: "Ali"}`
Type Checking [#type-checking]
A typed variable keeps its declared type. The analyzer rejects mismatches it can detect before execution; assignments from dynamic values are checked at runtime. A rejected assignment preserves the previous value. An integral floating-point value can be converted to `abn`, but a fractional value is rejected.
To require explicit variable types, run `soplang --strict file.sop`. Strict mode rejects `door` declarations. See [CLI & REPL](/docs/19_cli-and-repl).
Constants – madoor [#constants--madoor]
Use `madoor` to prevent reassignment. Its name is associated with *madoorsoome*. A list or object held by a constant can still be changed through mutating methods; the constant does not deeply freeze its contents.
**constants\_basic.sop**
Reassigning a constant produces an error:
**constants\_reassign\_error.sop**
Combine `madoor` with a static type to check the value's type as well:
**constants\_typed.sop**
# Type Conversion
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Type Conversion in Soplang [#type-conversion-in-soplang]
Soplang provides built-in functions for inspecting types and converting values. Use `abn()`, `jajab()`, `qoraal()`, and `bool()` for explicit conversions.
nooc() – Inspect a Type [#nooc--inspect-a-type]
Use `nooc()` to get the type name of a value.
**type\_checking.sop**
`nooc()` returns one of these type names:
Value
`nooc()`
`42`
`abn`
`3.14`
`jajab`
`"abc"`
`qoraal`
`run` / `been`
`bool`
`[1, 2]`
`teed`
`{a: 1}` or a class instance
`walax`
Function
`hawl`
`maran`
`maran`
Type Conversion Functions [#type-conversion-functions]
The following table shows common conversions:
Conversion
Function
Example
Int → String
`qoraal()`
`qoraal(42)`
String → Int
`abn()`
`abn("123")`
Float → String
`qoraal()`
`qoraal(3.14)`
String → Float
`jajab()`
`jajab("3.14")`
Int → Float
`jajab()`
`jajab(5)`
Float → Int
`abn()`
`abn(4.9)`
→
`4`
*(truncates)*
Any → Bool
`bool()`
`bool(1)`
→
`run`
,
`bool(0)`
→
`been`
bool() Rules [#bool-rules]
`bool()` returns `been` for `0`, `0.0`, `""`, `maran`, `been`, an empty list `[]`, an empty object `{}`, and the strings `"false"` and `"False"`. All other values produce `run`, including the string `"been"`.
Example [#example]
Input from `gelin()` is a string. Convert it to the type you need before using it in numeric calculations.
# Operators
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Operators in Soplang [#operators-in-soplang]
Soplang supports arithmetic, comparison, and logical operators.
Arithmetic Operators [#arithmetic-operators]
Use these operators with integers (`abn`) and floating-point numbers (`jajab`).
Operator
Meaning
Example
`+`
Addition
`a + b`
`-`
Subtraction
`a - b`
`*`
Multiplication
`a * b`
`/`
Division
`a / b`
`%`
Modulo
`a % b`
Comparison Operators [#comparison-operators]
Comparison operators test equality and ordering between values.
Operator
Meaning
Example
`==`
Equal
`a == b`
`!=`
Not equal
`a != b`
`>`
Greater than
`a > b`
`<`
Less than
`a < b`
`>=`
Greater or equal
`a >= b`
`<=`
Less or equal
`a <= b`
Logical Operators [#logical-operators]
Logical operators combine or negate boolean conditions.
Operator
Meaning
Example
`&&`
Logical AND
`(a > 5) && (b < 10)`
`||`
Logical OR
`(a < 5) || (b > 3)`
`!`
Logical NOT
`!(a == b)`
3) && (y < 15)
bool isMismatch = !(x == y)
qor("Is in range: " + isInRange)
qor("Mismatch: " + isMismatch)`}
/>
Operator Precedence [#operator-precedence]
Operators have the following precedence, from highest to lowest:
1. Unary: `!`, `-`
2. `*`, `/`, `%`
3. `+`, `-`
4. Comparison: `==`, `!=`, `>`, `<`, `>=`, `<=`
5. Logical: `&&`, `||`
Many languages give `&&` higher precedence than `||`. In Soplang, both have equal precedence and group from left to right: `run || been && been` evaluates to `been`. Use parentheses when combining them, such as `run || (been && been)`.
String Concatenation [#string-concatenation]
`+` also joins strings. When either operand is a string, the other value, such as a number, boolean, or list, is converted to text.
3
qor(natiijo) // run`}
/>
Division (`/`) can produce a fractional result: `10 / 4` is `2.5`. Division by zero (`x / 0`) produces a runtime error.
# Conditional Statements
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Conditional Statements [#conditional-statements]
Conditional statements choose which block to execute based on a condition or value.
If Statements – haddii and kale [#if-statements--haddii-and-kale]
`haddii` starts an *if* statement. Use `kale (condition)` for *else if* and `kale` without a condition for *else*.
= 18) {
qor("Waad qaan gaadhay")
} kale (da >= 13) {
qor("Waxaad tahay dhallinyaro")
} kale {
qor("Waad yar tahay")
}`}
/>
Enclose each block in `{}`. You can chain conditional branches or nest them inside other blocks.
Boolean Conditions [#boolean-conditions]
Use boolean expressions and the operators `&&`, `||`, and `!` to write conditions.
Summary [#summary]
Keyword
Meaning
`haddii`
if
`kale`
else if
`kale`
else
Switch-Case – dooro and xaalad [#switch-case--dooro-and-xaalad]
Use `dooro` to select a branch based on one expression. Each `xaalad` defines a case, and an optional `kale` defines the default branch.
Switch statements are useful when several branches depend on the same value.
`xaalad` supports both numbers and strings. Only the matching case executes; there is no fall-through, so `jooji` is unnecessary. The default `kale` branch is optional.
Combined Usage [#combined-usage]
You can combine `haddii`/`kale` branches with `dooro` statements to express more complex decisions.
# Loops
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Loops in Soplang [#loops-in-soplang]
Soplang supports `intay` (*while*) and `kuceli` (*for*) loops. Use `jooji` to break out of a loop and `soco` to continue with its next iteration.
While Loop – intay [#while-loop--intay]
The loop body repeats while its condition is `run`:
**while\_basic.sop**
Use `jooji` and `soco` to control execution:
**while\_break\_continue.sop**
For Loop – kuceli [#for-loop--kuceli]
The syntax is `kuceli (variable start ilaa end :: step)`. The end bound is **inclusive**. The `:: step` part is optional and defaults to `1`.
**for\_basic.sop**
Specify a step to change the increment:
**for\_step.sop**
A negative step counts downward. A zero step produces an error.
**count\_down.sop**
= 1) {
qor(i)
i = i - 1
}`}
/>
`ilaa` is contextual rather than globally reserved: it has its loop meaning inside `kuceli (...)`.
Loop Over a List [#loop-over-a-list]
**loop\_over\_list.sop**
Range with baaxad() [#range-with-baaxad]
`baaxad()` creates a list of integers, similar to Python's `range`. Its stop bound is **excluded**, unlike the inclusive end bound of `kuceli`.
Nested Loops [#nested-loops]
**nested\_loops.sop**
0) {
qor("Nested example")
jooji
}
}`}
/>
Factorial with While [#factorial-with-while]
**factorial\_while.sop**
0) {
result = result * n
n = n - 1
}
qor(result)`}
/>
Summary [#summary]
Keyword
Meaning
`intay`
while loop
`kuceli`
for loop
`jooji`
break
`soco`
continue
# Functions
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Functions in Soplang [#functions-in-soplang]
Functions are reusable blocks of code. Define a function with `hawl` and return a value with `celi`.
Define a Function – hawl [#define-a-function--hawl]
A function definition starts with `hawl`, followed by a name and parameters. Parameters may be untyped or explicitly typed.
Call a Function [#call-a-function]
Call a function by writing its name followed by arguments in parentheses:
Return Values – celi [#return-values--celi]
Use `celi` to return a value from a function.
A function without `celi`, or with a bare `celi`, returns `maran` (null). A bare `celi` can exit a function early:
Typed Parameters and Return Types [#typed-parameters-and-return-types]
Place a type before each parameter name, and add `: type` after `)` to annotate the return value. Known type mismatches are rejected during analysis; dynamic values are checked at runtime.
An argument with a known incompatible type is rejected before execution:
Recursion [#recursion]
A function can call itself:
Functions as Values [#functions-as-values]
Functions are values, and `nooc()` returns `"hawl"` for them. Store a function in a variable or pass it to a method such as `aaddin()` or `shaandhee()`. Use the function's name without quotes or a call's parentheses.
Scope [#scope]
Variables declared inside a function are local. Functions read the current values of global variables and can update them. Parameters and local declarations shadow global variables with the same name.
Loops Inside Functions [#loops-inside-functions]
Functions can contain loops and other control flow.
Summary [#summary]
Keyword
Meaning
`hawl`
function definition
`celi`
return value
Anonymous Functions and Closures [#anonymous-functions-and-closures]
`hawl(...) { ... }` creates an anonymous function. It can capture local values from its enclosing function:
Captured local values use snapshot semantics when the closure is created.
Global variables are read from their current shared value. Callback methods
validate that their argument is callable, including for empty lists. Argument
counts are checked for functions, methods, closures, built-ins and constructors.
The compiled call boundary accepts eight ABI values, including implicit receiver
or closure environment arguments. Defaults, keyword arguments, variadic user
functions and arbitrary callable expressions remain planned work.
# Data Types
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Data Types in Soplang [#data-types-in-soplang]
Soplang provides primitive values and collections. Declare a dynamic variable with `door`, or use a type keyword for an explicitly typed variable.
Primitive Types [#primitive-types]
Numbers [#numbers]
Soplang supports integers (`abn`) and binary floating-point numbers (`jajab`). Use `door` for a dynamic variable or `abn`/`jajab` for an explicitly typed declaration. See [Numbers](/docs/11_numbers).
**numbers.sop**
Strings [#strings]
Strings (`qoraal`) are sequences of Unicode characters. Use double quotes (`"..."`) or single quotes (`'...'`). Use `f"...{name}..."` to interpolate values, or join strings with `+`. See [Strings](/docs/10_strings).
**strings.sop**
Booleans [#booleans]
The boolean values are `run` (true) and `been` (false). Declare them with `door` or `bool`. Printing a boolean displays `run` or `been`.
**booleans.sop**
y) // been
qor(x <= y) // run
qor(x == 10) // run
qor(x != y) // run`}
/>
Null [#null]
`maran` represents the absence of a value. Printing it, or inspecting it with `nooc()`, produces `maran`. A function that returns no value also returns `maran`.
**maran.sop**
Collection Types [#collection-types]
Collections hold multiple values.
Lists [#lists]
Lists (`teed`) are ordered collections. Create a list using `[]`, with either `teed` or `door` in its declaration. See [Lists](/docs/12_arrays).
**lists.sop**
Objects [#objects]
Objects (`walax`) store string keys and their values. Create one using `{}`, with either `walax` or `door` in its declaration. See [Objects](/docs/13_objects).
**objects.sop**
Checking Types [#checking-types]
Use `nooc()` to inspect a value's type: `abn`, `jajab`, `qoraal`, `bool`, `teed`, `walax`, `hawl`, or `maran`. See [Type Conversion](/docs/04_type-conversion).
# Strings (qoraal)
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
A string (`qoraal`) is a sequence of Unicode characters. Use double quotes
(`"..."`) or single quotes (`'...'`). Plain strings preserve backslashes. Prefix a string with `e` to decode escapes
or with `f` to interpolate expressions. Triple quotes allow multiline text. String methods return new values
without changing the original string.
Escapes and interpolation [#escapes-and-interpolation]
An `r` prefix explicitly requests raw text. Plain strings also preserve
backslashes for compatibility. `e` strings decode escapes, including Unicode
escapes. `f` strings evaluate expressions inside `{...}` and accept format
specifiers. See the [language reference](https://github.com/soplang/soplang/blob/v3.6.0/docs/language/grammar.md)
for the literal syntax and [text methods](https://github.com/soplang/soplang/blob/v3.6.0/docs/language/text-methods.md)
for string operations.
Creation, Length, and Indexing [#creation-length-and-indexing]
Positions count Unicode scalar values, rather than UTF-8 bytes or grapheme
clusters. Negative indexes count from the end. An out-of-range read returns
`maran`, as do `hore()` and `dambe()` on an empty string. Both `dherer(text)`
and `text.dherer()` return the length.
Slicing and Search [#slicing-and-search]
| Method | Description |
| ------------------------ | ------------------------------------------------------------ |
| `hel(index, default?)` | Read one character or return the supplied default |
| `jar(start?, end?)` | Return a slice, excluding the end bound |
| `leeyahay(sub)` | Check whether the string contains a substring |
| `bilow(sub)` | Check whether the string starts with a substring |
| `dhammaad(sub)` | Check whether the string ends with a substring |
| `raadi(sub, direction?)` | Return the first or last matching index, or `-1` when absent |
| `tiri(sub)` | Count non-overlapping matches |
`jar()` requires integer bounds. Bounds outside the string are clamped, and
reversed bounds produce `""`. An optional direction for `raadi()` must be
`"hore"` (first) or `"dambe"` (last). `tiri("")` produces an error.
Search misses return `maran` for lists and `-1` for strings.
Trimming and Transformation [#trimming-and-transformation]
| Method | Description |
| -------------------------- | ---------------------------------------------------------------------- |
| `masax(direction?)` | Trim whitespace at both ends, or only `"hore"` / `"dambe"` |
| `weynee()` | Convert to uppercase using Unicode case conversion |
| `yaree()` | Convert to lowercase using Unicode case conversion |
| `beddel(old, new, count?)` | Replace the first match, a specified number of matches, or all matches |
| `kuceli(count)` | Repeat the string a specified number of times |
With two arguments, `beddel()` replaces the first match. Its third argument
may be a nonnegative integer limit, or `maran` to replace all matches. A limit
of `0` leaves the string unchanged. `kuceli()` requires a nonnegative integer.
Splitting and Joining [#splitting-and-joining]
`qeybi(separator)` returns a list of strings. `xiriiri(values)` joins the string
representations of list items, using the receiver as the separator.
These method names are shared with other language APIs where applicable.
Supported earlier names are listed in the
[reference](/docs/14_keywords-reference#compatibility-spellings).
# Numbers
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Numbers in Soplang [#numbers-in-soplang]
Soplang has two numeric types: **abn** (signed 64-bit integers) and **jajab**
(64-bit binary floating-point numbers). This guide covers literals, arithmetic,
comparisons, and conversions.
Integers — abn [#integers--abn]
`abn` represents whole numbers such as −2, −1, 0, 1, and 2. Use `door` for a
dynamic variable or `abn` for an explicitly typed declaration.
b) // run
qor(a == 10) // run
qor(a != b) // run`}
/>
Division (`/`) can produce a fractional result. Use `abn()` to truncate a
result toward zero when you need an integer.
Floating-Point Numbers — jajab [#floating-point-numbers--jajab]
`jajab` represents binary floating-point values. It supports fractional
calculations but does not provide exact decimal arithmetic.
3) // run
qor(2.0 == 2) // run (numeric values compare equally)`}
/>
When a `jajab` value is integral, such as `14.0`, `qor()` displays `14` without `.0`. Its type is still `jajab`; use `nooc()` to inspect it.
Use `nooc()` when you need to check the type held by a dynamic variable.
Mixing abn and jajab [#mixing-abn-and-jajab]
Arithmetic that mixes `abn` and `jajab` generally produces a `jajab` result.
Use `abn()` or `jajab()` for an explicit conversion.
Conversion Examples [#conversion-examples]
19
qor("Nooc: " + nooc(da)) // "abn"
// String → decimal
jajab qiime = jajab("12.75")
qor(qiime + 0.25) // 13
// Number → string
qoraal s = qoraal(2025)
qor("Sanad: " + s)`}
/>
Rounding — daji() and kor() [#rounding--daji-and-kor]
`daji()` rounds down toward negative infinity (floor). `kor()` rounds up toward
positive infinity (ceiling). Both return `abn`.
# Lists (teed)
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
A list (`teed`) is an ordered collection of values. Items may have different
types. Use `teed` for an explicitly typed declaration, or `door` for a dynamic
variable holding a list.
Creating and Reading Lists [#creating-and-reading-lists]
Indexes start at `0`; negative indexes count from the end. An out-of-range
read returns `maran`. `hel(index, default?)` returns the supplied default
only when the position is absent. A stored `maran` value is returned unchanged.
`hore()` and `dambe()` return `maran` for an empty list.
Adding, Replacing, and Removing Items [#adding-replacing-and-removing-items]
| Method | Description |
| -------------------- | ----------------------------------------------------------- |
| `geli(value)` | Append one value, including when that value is another list |
| `geli(index, value)` | Insert one value at the specified position |
| `dhig(index, value)` | Replace an existing item without creating a new position |
| `saar()` | Remove and return the last item |
| `saar(index)` | Remove and return the item at that position |
| `nadiifi()` | Remove all items |
Calling `saar()` on an empty list or writing to an out-of-range position
produces a catchable error. Other mutating list methods return the original list.
Combining and Copying [#combining-and-copying]
`midee(other)` returns a **new list**. `nuqul()` and `jar()` also create new
lists. These copies are shallow: nested lists and objects remain shared with
the original.
The end bound of `jar(start?, end?)` is excluded. Bounds must be integers and
are clamped to the list's length. Reversed bounds produce an empty list.
`jar()` without arguments copies the entire list.
Search, Counting, and Sorting [#search-counting-and-sorting]
| Method | Result |
| ----------------- | ------------------------------------------------ |
| `leeyahay(value)` | `run` when the value is present |
| `raadi(value)` | The first matching index, or `maran` when absent |
| `tiri(value)` | The number of matching items |
| `rog()` | Reverse the original list in place |
| `habee()` | Sort the original list in place |
Numbers are sorted numerically. Lists containing mixed types use the runtime's
comparison rules; do not assume Somali collation or a uniform numeric ordering
across types. A successful search may return `0`, so test explicitly for
`maran` when checking for a missing item. Collection equality distinguishes
`abn` from `jajab`.
Callback Methods [#callback-methods]
| Method | Description |
| -------------------------- | --------------------------------------------------------------------- |
| `aaddin(callback)` | Transform each item and return a new list |
| `shaandhee(callback)` | Return the items that satisfy the condition |
| `ururi(callback, initial)` | Fold left; the callback receives the accumulated result and next item |
| `dhammaan(callback)` | Check whether all items satisfy the condition |
| `qaar(callback)` | Check whether at least one item satisfies the condition |
0 })) // run
qor(tirooyin.qaar(hawl(x) { celi x > 3 })) // run`}
/>
Iteration uses a shallow snapshot taken at the start. A callback may change
the original list without changing the remaining iteration sequence. A callback
error stops the operation and propagates to `qabo`. `dhammaan()` and `qaar()`
stop as soon as the result is known; on an empty list they return `run` and
`been`, respectively.
Supported earlier names and the different overloads of `kudar()` are explained
in the [reference](/docs/14_keywords-reference#compatibility-spellings).
# Objects (walax)
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
An object (`walax`) stores key-value pairs. Keys are strings, and values may
have any type. In an object literal, write a key as an identifier or a quoted
string.
Creating and Accessing Objects [#creating-and-accessing-objects]
Both dot notation and bracket notation support reads and writes.
`hel(key, default?)` uses the default only when the key is absent. A present
key storing `maran` still returns `maran`. Reading a missing key without a
default returns `maran`.
Shared Methods [#shared-methods]
| Method | Result |
| -------------------- | -------------------------------------------------------------- |
| `dherer()` | The number of keys; `dherer(obj)` is also valid |
| `leeyahay(key)` | Check whether the key exists |
| `hel(key, default?)` | Return the value or the supplied default |
| `dhig(key, value)` | Set a value and return the original object |
| `saar(key)` | Remove and return the value, or `maran` when the key is absent |
| `nadiifi()` | Remove all keys and return the original object |
| `nuqul()` | Return a shallow copy |
| `midee(other)` | Return a new merged object |
The earlier method `tir(key)` remains supported, but returns the object itself.
`saar(key)` returns the removed value instead.
Keys, Values, and Pairs [#keys-values-and-pairs]
`furayaal()`, `qiimayaal()`, and `lammaanayaal()` all follow sorted-key order.
Merging and Copying [#merging-and-copying]
`midee()` leaves both inputs unchanged. When a key appears in both objects,
the right-hand object's value wins. The result is a shallow copy; nested
collections remain shared with the inputs.
Objects do not have built-in `hore()` or `dambe()` methods. Those methods
apply to lists and strings. See the
[reference](/docs/14_keywords-reference#object-methods).
# Soplang 3 Language Reference
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
This reference targets **Soplang 3.6.0**. Prefer the canonical names in new programs; supported earlier spellings are listed under Compatibility spellings.
This page covers the core syntax and collection API. The [full language reference](https://github.com/soplang/soplang/blob/v3.6.0/docs/language/keywords.md) also covers the 3.6 file, network, task, web, and data APIs.
The [terminology review](https://github.com/soplang/soplang/blob/v3.6.0/docs/language/terminology.md) records current names, source evidence,
and naming decisions. This reference uses implemented canonical spellings;
compatibility names are listed below. The collection design record explains shared operation contracts.
Variable Declaration Keywords [#variable-declaration-keywords]
| Keyword | Meaning | English Equivalent | Example |
| -------- | ----------------------------- | ------------------ | -------------------------------------- |
| `door` | Dynamic variable declaration | `var`/`let` | `door magac = "Sharafdin"` |
| `madoor` | Constant variable declaration | `const` | `madoor PI = 3.14159` |
| `abn` | Integer type | `int` | `abn da = 25` |
| `jajab` | Binary floating-point type | `float`/`double` | `jajab qiimo = 3.14` |
| `qoraal` | String type | `string` | `qoraal magac = "Sharafdin"` |
| `bool` | Boolean type | `bool` | `bool waaRun = run` |
| `walax` | Object type | `object` | `walax person = { name: "Sharafdin" }` |
| `teed` | List/array type | `array` | `teed numbers = [1, 2, 3]` |
| `xirmo` | Immutable tuple type | `tuple` | `xirmo row = xirmo(1, "Ayaan")` |
| `urur` | Set type | `set` | `urur items = urur(1, 2)` |
| `maran` | Null value | `null` | `door a = maran` |
Control Flow Keywords [#control-flow-keywords]
| Keyword | Meaning | English Equivalent | Example |
| -------- | -------------------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------- |
| `haddii` | If statement | `if` | `haddii (x > 10) { qor("Weyn") }` |
| `kale` | Else if statement | `else if` | `kale (x == 10) { qor("Dhexe") }` |
| `kale` | Else/default statement | `else` | `kale { qor("Yar") }` |
| `dooro` | Switch statement | `switch` | `dooro (x) { xaalad 1 { qor("Hal") } }` |
| `xaalad` | Case clause | `case` | `xaalad "A" { qor("Case A") }` |
| `kuceli` | For loop | `for` | `kuceli (i 1 ilaa 5) { qor(i) }` |
| `ilaa` | Loop range end | `to` | `kuceli (i 1 ilaa 5) { qor(i) }` |
| `::` | Loop step/increment amount (optional, follows the range) | `step` | `kuceli (i 1 ilaa 10 :: 2) { qor(i) }` — loops from 1 to 10, incrementing `i` by 2 each time |
| `intay` | While loop | `while` | `intay (x < 5) { qor(x) }` |
| `jooji` | Break statement | `break` | `haddii (x == 3) { jooji }` |
| `soco` | Continue statement | `continue` | `haddii (x == 3) { soco }` |
`kale` is contextual. After an `haddii` branch, `kale (condition) { ... }`
adds another conditional branch, while `kale { ... }` is the fallback. Inside
`dooro`, `kale { ... }` supplies the default case. Existing names such as
`hawl kale(x)` and calls such as `kale(1)` remain valid; a conditional branch
header must be followed by `{`.
Function Keywords [#function-keywords]
| Keyword | Meaning | English Equivalent | Example |
| ------- | -------------------- | ------------------ | ---------------------------------- |
| `hawl` | Function declaration | `function` | `hawl isuGee(a, b) { celi a + b }` |
| `celi` | Return statement | `return` | `celi x * 2` |
Special Values [#special-values]
| Somali Value | English Equivalent | Description | Example |
| ------------ | ------------------ | ------------------- | ------------------------ |
| `run` | `true` | Boolean true value | `haddii (run) { ... }` |
| `been` | `false` | Boolean false value | `haddii (!been) { ... }` |
| `maran` | `null` | Empty/null value | `door val = maran` |
`maran` is the canonical null literal. `null` remains accepted as a compatibility spelling. An empty string, list, or object is a value of its own type, distinct from `maran`.
Data Types [#data-types]
| Somali Type | English Equivalent | Description | Example |
| ----------- | ------------------ | ----------------------------- | -------------------------------- |
| `abn` | `int` | Integer numbers | `abn age = 25` |
| `jajab` | `float`/`double` | Binary floating-point numbers | `jajab pi = 3.14` |
| `qoraal` | `string` | Text values | `qoraal name = "Ahmed"` |
| `bool` | `boolean` | Truth values | `bool isValid = run` |
| `teed` | `list`/`array` | List of items | `teed numbers = [1, 2, 3]` |
| `walax` | `object` | Key-value pairs | `walax person = { name: "Ali" }` |
`abn` uses signed 64-bit integers. `jajab` uses 64-bit binary floating-point
values; it does not provide exact decimal arithmetic. `qoraal` is a string,
`teed` is a mutable list, and `walax` stores string keys and values.
`door`, `madoor`, and `abn` are Soplang short identifiers. The terminology
review relates them to *doorsoome*, *madoorsoome*, and *abyoone*, respectively;
these explanations do not establish a historical abbreviation or SLS approval.
Operators [#operators]
| Somali Operator | English Equivalent | Description | Example |
| --------------- | ------------------ | ------------------------ | ------------------------- |
| `+` | `+` | Addition | `x = a + b` |
| `-` | `-` | Subtraction | `x = a - b` |
| `*` | `*` | Multiplication | `x = a * b` |
| `/` | `/` | Division | `x = a / b` |
| `%` | `%` | Modulo | `x = a % b` |
| `==` | `==` | Equal to | `haddii (a == b) {...}` |
| `!=` | `!=` | Not equal to | `haddii (a != b) {...}` |
| `>` | `>` | Greater than | `haddii (a > b) {...}` |
| `<` | `<` | Less than | `haddii (a < b) {...}` |
| `>=` | `>=` | Greater than or equal to | `haddii (a >= b) {...}` |
| `<=` | `<=` | Less than or equal to | `haddii (a <= b) {...}` |
| `&&` | `&&` | Logical AND | `haddii (a && b) {...}` |
| `\|\|` | `\|\|` | Logical OR | `haddii (a \|\| b) {...}` |
| `!` | `!` | Logical NOT | `haddii (!a) {...}` |
> **Note:** Soplang supports the use of comparison operators directly in expressions without requiring additional parentheses. For example, `door x = a > b` is valid syntax to store the result of a comparison in a variable.
Built-in Functions [#built-in-functions]
| Function | Meaning | English Equivalent | Example |
| --------- | --------------------------------------------------------------- | ------------------ | -------------------------------------------- |
| `qor` | Print to console | `print` | `qor("Salaan, Adduunka!")` |
| `gelin` | Read input from user | `input` | `door magac = gelin("Magacaaga geli: ")` |
| `nooc` | Get type of variable | `typeof` | `qor(nooc(magac))` |
| `abn` | Convert value to an integer (also the `int` type keyword above) | `int` | `door n = abn("5")` |
| `jajab` | Convert a number or numeric string to floating point | `float` | `door n = jajab("3.5")` |
| `qoraal` | Convert to string | `str` | `door s = qoraal(25)` |
| `bool` | Convert to boolean | `bool` | `door b = bool(1)` |
| `teed` | Create a list | `list/array` | `door list = teed(1, 2, 3)` |
| `walax` | Create an object | `object/dict` | `door obj = walax("name", "Ali", "age", 25)` |
| `daji` | Round down to integer | `Math.floor()` | `door n = daji(4.7)` |
| `kor` | Round up to integer | `Math.ceil()` | `door n = kor(4.2)` |
| `dherer` | Count list items, object keys, or string characters | `len()`/`.length` | `door n = dherer(qoraal)` |
| `xul` | Get random value | `random()` | `door n = xul(1, 6)` |
| `baaxad` | Create an integer range | `range()` | `door n = baaxad(1, 5)` |
| `duub` | Round to the nearest integer | `round()` | `door n = duub(4.6)` |
| `sugan` | Get the absolute value | `abs()` | `door n = sugan(-5)` |
| `yar` | Get the smallest numeric argument | `min()` | `door n = yar(4, 2, 8)` |
| `weyn` | Get the largest numeric argument | `max()` | `door n = weyn(4, 2, 8)` |
| `jibbaar` | Raise a number to a power | `pow()` | `door n = jibbaar(2, 3)` |
| `xidid` | Calculate a square root | `sqrt()` | `door n = xidid(9)` |
`daji()` rounds toward negative infinity and `kor()` toward positive infinity.
`duub()` rounds to the nearest integer, with halfway values rounded away
from zero. `xidid()` computes only a square root, not an arbitrary root.
`xul()` returns a floating-point number in `[0, 1)`. `xul(a, b)` returns a floating-point number in `[a, b)`. `xul(teed)` returns one item and reports an error for an empty list.
> **Note:** `abn`, `qoraal`, `bool`, `teed`, and `walax` are used both as static **type keywords** (see Variable Declaration Keywords / Data Types above) and as **built-in conversion/constructor functions** here. The meaning depends on context: e.g. `abn age = 25` declares a typed variable, while `abn("5")` converts a string to a number.
baaxad (Range) [#baaxad-range]
`baaxad()` is a built-in function that creates a list of integers.
Unlike a lazy range iterator, it creates a list containing all the requested
integers. The stop bound is excluded.
**Usage:**
`baaxad` accepts integers only. A zero step reports an error that can be caught with `tijaabi` and `qabo`.
Shared collection operations [#shared-collection-operations]
Lists and objects share `dherer`, `leeyahay`, `hel`, `dhig`, `saar`, `nadiifi`,
and `nuqul` where applicable. Strings share `dherer`, `leeyahay`, and `hel`;
strings remain immutable.
* `hel(position, default?)` reads a list item or Unicode character;
`hel(key, default?)` reads an object value. Missing entries return the supplied
default or `maran`. A present `maran` value is returned unchanged. Defaults
are evaluated normally even when an entry exists.
* List and string positions must be integers and may be negative. Object keys
must be strings. Invalid argument types report catchable errors.
* `dhig(index, value)` replaces an existing list item; `dhig(key, value)` inserts
or replaces an object entry. Both mutate and return the receiver. An invalid
list position reports an error before mutation; use `geli` for insertion.
* List `saar()` removes the last item; `saar(index)` removes an indexed item.
Both return the removed value and reject empty or out-of-range removals.
Object `saar(key)` returns the removed value or `maran` for a missing key.
* `nadiifi()` mutates and returns the receiver. `nuqul()` returns a shallow copy.
Slicing, endpoints, counting, and search [#slicing-endpoints-counting-and-search]
Lists and strings accept `jar()`, `jar(start)`, or `jar(start, end)`. Bounds
must be integers. The default start is zero and the default end is the length;
negative bounds count from the end. Bounds are clamped to the collection. The
start is included and the end excluded. Equal or reversed normalized bounds
produce an empty result. Slicing leaves the receiver unchanged; list slices are
shallow copies. String positions count Unicode characters.
`hore()`/`dambe()` return the first/last item or character, or `maran` when
empty. List `tiri(value)` counts matching values using the same equality rules
as list membership and search, including structural collection equality and
distinct integer/float values. String `tiri(sub)` counts non-overlapping matches
and rejects an empty substring.
Search has one compatibility exception: missing list `raadi`/`muuji` results
are `maran`, while string `raadi`/`raadi_dambe` results are `-1`. A successful
search returns an integer position, including zero. Test misses explicitly
rather than relying on the truthiness of a search result.
List Methods [#list-methods]
| Method | English Equivalent | Description | Example |
| ---------------------- | ------------------------- | -------------------------------------------------- | ---------------------------------------------------------- |
| `dherer()` | `length()` | Get list length | `numbers.dherer()` |
| `hel(index, default?)` | `get()` | Read by index or return a default | `numbers.hel(-1, maran)` |
| `dhig(index, value)` | indexed assignment | Replace an existing item and return the list | `numbers.dhig(0, 5)` |
| `geli(item)` | `push()` or `append()` | Add item to the original list | `numbers.geli(5)` |
| `saar()` | `pop()` | Remove and return last item | `door last = numbers.saar()` |
| `midee(teed)` | `concat()` | Concatenate lists | `door all = list1.midee(list2)` |
| `leeyahay(x)` | `contains()`/`includes()` | Check if item exists | `haddii (list.leeyahay(x)) {...}` |
| `nuqul()` | `copy()` | Create a shallow copy | `door copy = list.nuqul()` |
| `nadiifi()` | `clear()` | Remove all items from the original list | `list.nadiifi()` |
| `rog()` | `reverse()` | Reverse the original list | `list.rog()` |
| `habee()` | `sort()` | Sort the original list in ascending order | `list.habee()` |
| `jar(start?, end?)` | `slice(a, b)` | Return a new list; start included, end excluded | `door subset = numbers.jar(1, 3)` |
| `aaddin(func)` | `map(func)` | Transform items with function | `door doubled = nums.aaddin(hawl(x) { celi x * 2 })` |
| `shaandhee(func)` | `filter(func)` | Filter items with function | `door evens = nums.shaandhee(hawl(x) { celi x % 2 == 0 })` |
| `raadi(item)` | `indexOf(item)` | Find index of item | `door idx = nums.raadi(5)` |
| `tiri(value)` | `count()` | Count equal list items | `numbers.tiri(5)` |
| `geli(index, item)` | `insert(index, item)` | Insert into the original list | `numbers.geli(1, 5)` |
| `saar(index)` | `remove(index)` | Remove and return an indexed item | `door item = numbers.saar(1)` |
| `hore()` | `first()` | Return first item or `maran` | `door item = numbers.hore()` |
| `dambe()` | `last()` | Return last item or `maran` | `door item = numbers.dambe()` |
| `ururi(func, bilow)` | `reduce(func, initial)` | Fold with an arbitrary callback, not only addition | `nums.ururi(hawl(a, b) { celi a + b }, 0)` |
| `dhammaan(func)` | `every(func)` | Test whether every item matches | `nums.dhammaan(hawl(x) { celi x > 0 })` |
| `qaar(func)` | `some(func)` | Test whether any item matches | `nums.qaar(hawl(x) { celi x == 5 })` |
`midee(teed)` returns a concatenated copy without mutating either input. `geli(item)` always appends one item, including a nested list. `nuqul()` and `jar()` also return new lists. `saar()` and `saar(index)` return the removed value. Methods that otherwise mutate a list return the original list after changing it. Nested lists and objects remain shared when copied.
`hore()` and `dambe()` return the first and last list items without modifying
the list. Strings use the same names for Unicode characters. Both return
`maran` for an empty receiver. Objects have no built-in
positional first/last methods.
`raadi(item)` returns the first matching index or `maran` when no item matches.
`ururi(func, bilow)` is a general left fold: its callback receives the
accumulated value and the next item. It can multiply values, construct text, or
perform other accumulation; its behavior is not restricted to summation.
Map, filter, fold, every, and some validate callbacks even on empty lists.
Each iterates a shallow snapshot, allowing callbacks to modify the original
list without changing the remaining iteration sequence. Callback errors stop
the operation and propagate to `qabo`. `dhammaan` and `qaar` stop at the first
decisive result; on an empty list they return `run` and `been`, respectively.
Object Methods [#object-methods]
| Method | English Equivalent | Description | Example |
| -------------------- | -------------------- | ------------------------------ | ------------------------------------- |
| `dherer()` | `length()` | Count keys | `obj.dherer()` |
| `furayaal()` | `keys()` | Get all keys | `door keys = obj.furayaal()` |
| `qiimayaal()` | `values()` | Get all values | `door values = obj.qiimayaal()` |
| `lammaanayaal()` | `entries()` | Get key-value pairs | `door pairs = obj.lammaanayaal()` |
| `leeyahay(x)` | `hasOwnProperty()` | Check if key exists | `haddii (obj.leeyahay("name")) {...}` |
| `midee(obj)` | `merge()`/`assign()` | Return a merged copy | `door merged = obj1.midee(obj2)` |
| `nuqul()` | `copy()` | Create a shallow copy | `door copy = obj.nuqul()` |
| `nadiifi()` | `clear()` | Remove all original properties | `obj.nadiifi()` |
| `hel(key, default?)` | `get()` | Get a key or optional default | `obj.hel("name", "Unknown")` |
| `dhig(key, value)` | `set()` | Set a computed key | `obj.dhig("name", "Ali")` |
| `saar(key)` | `remove()` | Remove and return a value | `door old = obj.saar("name")` |
Objects also support computed bracket access: `obj["name"]` and `obj["name"] = "Ali"`. Object `nuqul()` is shallow: nested lists and objects remain shared. `tir(key)` returns the object, whereas `saar(key)` returns the removed value or `maran`.
Object key, value, and pair lists follow sorted-key order. `midee` returns a
new shallow object; the right input wins overlapping keys. Neither input is
mutated.
String Methods [#string-methods]
| Method | English Equivalent | Description | Example |
| ------------------------ | ------------------ | --------------------------------------------------------- | ---------------------------------------- |
| `hore()` | first character | First Unicode character or `maran` | `text.hore()` |
| `dambe()` | last character | Last Unicode character or `maran` | `text.dambe()` |
| `hel(index, default?)` | character lookup | Read a Unicode character or return a default | `text.hel(-1, "")` |
| `qeybi(xad)` | `split()` | Split string by delimiter | `door parts = text.qeybi(",")` |
| `leeyahay(sub)` | `includes()` | Check if string contains substring | `haddii (text.leeyahay("search")) {...}` |
| `dhammaad(sub)` | `endsWith()` | Check if string ends with substring | `haddii (text.dhammaad("ing")) {...}` |
| `bilow(sub)` | `startsWith()` | Check if string starts with substring | `haddii (text.bilow("http")) {...}` |
| `beddel(x, y, count?)` | `replace()` | Replace first match, a limited count, or all with `maran` | `door new = text.beddel("old", "new")` |
| `xiriiri(teed)` | `join()` | Join string representations with separator | `door text = ", ".xiriiri(names)` |
| `jar(start?, end?)` | `slice()` | Slice by character position | `door sub = text.jar(0, 3)` |
| `weynee()` | `toUpperCase()` | Convert string to uppercase | `door n = q.weynee()` |
| `yaree()` | `toLowerCase()` | Convert string to lowercase | `door n = q.yaree()` |
| `masax(direction?)` | `trim()` | Trim both ends, or `"hore"`/`"dambe"` | `door n = q.masax()` |
| `raadi(sub, direction?)` | `indexOf()` | Find first/last character index | `door n = q.raadi("pro")` |
| `dherer()` | `length` | Count Unicode characters | `door n = q.dherer()` |
| `tiri(sub)` | `count()` | Count non-overlapping occurrences | `door n = q.tiri("ab")` |
| `kuceli(n)` | `repeat()` | Repeat the string | `door n = q.kuceli(3)` |
String positions and bracket indexes count characters rather than UTF-8 bytes. `jar()` and bracket indexing accept negative positions from the end. Missing indexes return `maran`; `raadi()` returns `-1` when it finds no match. Calls with the wrong number of arguments report an error that can be caught with `tijaabi` and `qabo`.
weynee (Uppercase) [#weynee-uppercase]
**Usage:**
yaree (Lowercase) [#yaree-lowercase]
**Usage:**
masax (Trim Whitespace) [#masax-trim-whitespace]
**Usage:**
raadi (Find Substring) [#raadi-find-substring]
**Usage:**
beddel (Replace All) [#beddel-replace-all]
**Usage:**
`masax()` trims both ends; `masax("hore")` trims only leading whitespace and
`masax("dambe")` only trailing whitespace. `raadi(sub)` and `raadi(sub, "hore")`
search from the beginning; `raadi(sub, "dambe")` returns the last match.
Unsupported direction values report catchable errors.
`beddel(old, new)` replaces the first occurrence. A third nonnegative integer
limits replacements; zero leaves the text unchanged. Passing `maran` as the
third argument replaces all occurrences. Empty search text matches character
boundaries. `xiriiri(list)` joins the string representations of values, including
non-string values. `weynee` and `yaree` use Unicode case conversion. `kuceli`
requires a nonnegative integer count and is accepted after a dot without changing
the numeric loop syntax.
Object-Oriented Programming (OOP) [#object-oriented-programming-oop]
| Keyword / concept | Meaning | English | Example |
| ----------------- | ------------------------------------------- | --------------- | ------------------------------------------ |
| `qaab` | Class definition | `class` | `qaab Bisad { ... }` |
| `dhaxal` | Inherit from parent class | `extends` | `qaab Bisad dhaxal Xayawaan { ... }` |
| `cusub` | Create a new instance | `new` | `door b = cusub Bisad("Mia")` |
| `nafta` | Current instance (self) | `this` / `self` | `nafta.magac = magac` |
| `waalid` | Call a method on the parent class | `super` | `celi waalid.cod()` |
| `dhis` | Constructor method (auto-called by `cusub`) | `constructor` | `hawl dhis(magac) { nafta.magac = magac }` |
**Class example:**
Notes:
* Class bodies may contain only `hawl` (method) definitions.
* `nafta` is injected automatically as the first parameter of every class method.
* Instance fields are stored as object properties; read them with `obj.field`.
* Method lookup walks the inheritance chain (child overrides parent).
Modules and error handling [#modules-and-error-handling]
| Keyword | Meaning | English | Example |
| --------- | ---------------------------------- | --------- | ---------------------------------- |
| `keen` | Import another `.sop` file | `import` | `keen "lib.sop"` |
| `tijaabi` | Start a protected try block | `try` | `tijaabi { ... } qabo (e) { ... }` |
| `qabo` | Catch block with error variable | `catch` | `qabo (fariin) { qor(fariin) }` |
| `tuur` | Raise a string or structured error | `raise` | `tuur "Xog ma jirto"` |
| `dhammee` | Guaranteed cleanup | `finally` | `tijaabi { ... } dhammee { ... }` |
**Import example:**
Imported files are resolved relative to the current file's directory. Top-level definitions (functions, variables, classes) from the imported file become available in the importing program.
**Try/catch example:**
Runtime errors inside the `tijaabi` block are caught; the first `qabo` variable receives the message. An optional second variable receives a structured error. `tuur` raises an error, and `dhammee` runs on exit. See [error handling](/docs/17_error-handling).
Compatibility spellings [#compatibility-spellings]
| Canonical API | Supported earlier spelling |
| ---------------------------------------------------- | ----------------------------------------------------------- |
| Constructor `dhis()` | `dhaw()` |
| Try block `tijaabi { ... } qabo (e) { ... }` | `fasax { ... } qabo (e) { ... }` |
| `jibbaar(a, b)` | `awood(a, b)` |
| List `raadi(item)` | `muuji(item)` |
| String `dhammaad(suffix)` | `dhamaad(suffix)` |
| List `saar()` | `kasaar()` |
| List `saar(index)` | `ka_saar(index)` |
| Object `saar(key)` | `ka_qaad(key)` |
| Object removal returning the receiver | `tir(key)`; different return contract from `saar` |
| List `hore()` | `koowaad()` |
| List `dambe()` | `ugu_dambeeya()` |
| `yar(...)` | `ugu_yar(...)` |
| `weyn(...)` | `ugu_weyn(...)` |
| List `ururi(func, initial)` | `isku_gee(func, initial)` |
| List/object `midee(other)` | `kudar(other)`; list argument concatenates without mutation |
| String `xiriiri(list)` | `kudar(list)` |
| String `weynee()` | `xarfaha_waaweyn()`, `xarafaha_weyn()` |
| String `yaree()` | `xarfaha_yaryar()` |
| String `masax("hore")` | `masax_bilow()` |
| String `masax("dambe")` | `masax_dhammaad()`, `masax_dhamaad()` |
| String `raadi(sub, "dambe")` | `raadi_dambe(sub)` |
| String `beddel(old, new, maran)` | `beddel_dhammaan(old, new)` |
| String `kuceli(count)` | `ku_celi(count)` |
| `duub(value)` | `dhammeystir(value)` |
| Object `furayaal()`, `qiimayaal()`, `lammaanayaal()` | `fure()`, `qiime()`, `lamaane()` |
| `kale (condition) { ... }` | `haddii_kale (condition) { ... }` |
| `kale { ... }` | `ugudambeyn { ... }` in conditionals and switches |
`tijaabi` is contextual: it starts a try block only before `{`. Existing
variables, functions, and properties named `tijaabi` remain valid. `qabo` is
unchanged.
Automatic construction searches the nearest class first, preferring its `dhis`
over its `dhaw`, then walks to its parent. Explicit constructor calls, including
`waalid.dhis()` and `waalid.dhaw()`, prefer the requested spelling in each class
and fall back to the other spelling before moving to the next ancestor. If a
class defines both, both methods remain explicitly callable.
Legacy object `tir(key)` remains supported and returns the receiver; it is not
a direct alias of `saar(key)`, which returns the removed value. Existing `kudar`
overloads also preserve their mutation and copying behavior.
List `kudar(value)` retains its original type-dependent behavior: scalar values
append in place, while a list argument produces a concatenated copy. Prefer
`geli(value)` for adding exactly one item, including a nested list, and `midee`
for combining collections.
Global updates [#global-updates]
Functions, methods, and callbacks share the current value of a global variable
with top-level code. Global variables take precedence over built-in names,
matching local shadowing. Replacing a scalar, list, object, or callable is visible on
the next read. Function parameters and local declarations still shadow globals;
closure captures of enclosing local variables retain their existing snapshot
semantics.
Top-level numeric loop indexes are published to globals and can be read or
updated by functions during the loop. The increment uses the current index,
including any update from the body. The final index remains available after
the loop; `jooji` preserves the index at the break.
Typed global writes inside functions enforce the same type and class checks as
top-level writes. Rejected assignments preserve the previous global value.
An accepted integral float is converted to `abn` for an integer annotation, and
an accepted integer is converted to `jajab` for a floating-point annotation,
keeping the representation consistent with native arithmetic. Fractional floats
are rejected for `abn` annotations; use `abn(value)` for explicit truncation.
# Built-in Functions in Soplang
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Built-in Functions in Soplang [#built-in-functions-in-soplang]
Built-in functions are available without imports. They cover printing, user
input, type inspection and conversion, collection creation, numeric operations,
and ranges. Soplang 3.6 also provides `khalad`, `xirmo`, `urur`,
`sug`, channels, file and network functions, and bundled modules. See the
[3.6 overview](/docs/21_soplang-3-6) and [full reference](https://github.com/soplang/soplang/blob/v3.6.0/docs/language/keywords.md)
for their arguments and behavior.
Core Built-in Function Reference [#core-built-in-function-reference]
Function
Meaning
English Equivalent
Example
qor()
Print to console
print()
qor("Salaan, Adduunka!")
gelin()
Read user input
input()
door magac = gelin("Magacaaga geli: ")
nooc()
Get type of a value
typeof
qor(nooc(magac))
abn()
Convert to integer
int()
door n = abn("5")
jajab()
Convert to float
float()
door f = jajab("3.14")
qoraal()
Convert to string
str()
door s = qoraal(25)
bool()
Convert to boolean
bool()
door b = bool(1)
teed()
Create an array
list()
door liis = teed(1, 2, 3)
walax()
Create an object
object()
door obj = walax("magac", "Ali")
daji()
Round down
Math.floor()
door x = daji(4.9)
kor()
Round up
Math.ceil()
door x = kor(4.2)
dherer()
Length of string, list, or object
len()/.length
door l = dherer("text")
xul()
Random number or random list item
random()
door n = xul(1, 6)
baaxad()
Create a list of numbers (range)
range()
door l = baaxad(1, 5)
Notes [#notes]
* **`walax()`** accepts alternating key-value arguments, such as `walax("magac", "Ali", "da", 20)`. An object literal is often simpler: `{magac: "Ali", da: 20}`.
* **`dherer()`** works on strings, lists, and objects. All three also support a `.dherer()` method.
* **`xul()`** supports three forms:
* `xul()` returns a random floating-point number in `[0, 1)`.
* `xul(a, b)` returns a random floating-point number in `[a, b)`. For an integer from `1` through `6`, use `daji(xul(1, 7))`.
* `xul(list)` returns one randomly chosen list item.
* **`baaxad()`** creates a list of integers, excluding the stop bound: `baaxad(5)` produces `[0, 1, 2, 3, 4]`, `baaxad(2, 6)` produces `[2, 3, 4, 5]`, and `baaxad(1, 10, 2)` produces `[1, 3, 5, 7, 9]`.
* **`daji()` / `kor()`** return `abn` values.
Examples [#examples]
**builtins\_examples.sop**
Numeric Helpers in Soplang 3 [#numeric-helpers-in-soplang-3]
| Function | Description | Example |
| --------------- | ------------------------------------------------------ | --------------------------- |
| `duub(x)` | Round to the nearest integer, with ties away from zero | `duub(-2.5)` returns `-3` |
| `sugan(x)` | Return the absolute value | `sugan(-5)` returns `5` |
| `yar(...)` | Return the smallest numeric argument | `yar(4, 2, 8)` returns `2` |
| `weyn(...)` | Return the largest numeric argument | `weyn(4, 2, 8)` returns `8` |
| `jibbaar(a, b)` | Raise a number to a power | `jibbaar(2, 3)` returns `8` |
| `xidid(x)` | Return the square root | `xidid(9)` returns `3` |
`xul()` and `xul(a, b)` exclude the upper bound. Passing an empty list to
`xul(list)` produces an error. `baaxad()` accepts integers only and rejects
a zero step. Each function validates its argument count.
General file I/O, HTTP, and network functions remain planned work.
# Classes
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Classes in Soplang [#classes-in-soplang]
Define a class with `qaab` and create an instance with `cusub`. Inside a method,
`nafta` refers to the current instance.
| Keyword | Meaning | English Equivalent |
| -------- | ------------------------------ | ------------------ |
| `qaab` | Define a class | `class` |
| `dhis` | Constructor, called by `cusub` | `constructor` |
| `nafta` | The current instance | `this` / `self` |
| `cusub` | Create an instance | `new` |
| `dhaxal` | Inherit from another class | `extends` |
Defining a Class – qaab [#defining-a-class--qaab]
A class body may contain **method definitions only**. Store instance data as
fields on `nafta`, usually from the `dhis` constructor.
Creating Instances – cusub [#creating-instances--cusub]
`cusub` creates an instance and automatically calls `dhis` with the supplied
arguments.
A class without a constructor can also be instantiated, for example with
`cusub Tiriye()`.
Inheritance – dhaxal [#inheritance--dhaxal]
Use `dhaxal` to inherit from another class. The child inherits the parent's
methods, including `dhis`, and can override a method by defining one with the
same name.
Although `sharax()` is defined on `Xayawaan`, its call to `nafta.cod()` uses
the method belonging to the actual instance's class.
Objects in Collections [#objects-in-collections]
Instances are ordinary values: you can store them in lists, pass them to
functions, and return them from functions.
Rules [#rules]
* Class bodies accept `hawl` method definitions only. A declaration such as `door x = 1` directly inside a class produces a parser error.
* `dhis` is the constructor name and is called automatically by `cusub`.
* `nafta` is added to each method automatically; do not declare it as a parameter.
* Method lookup starts at the instance's class and follows its parent chain.
Parent Calls and Class Annotations [#parent-calls-and-class-annotations]
`waalid` starts method lookup at the parent of the class that defined the current
method. A variable annotated with a parent class can hold a child instance:
Inheritance cycles and invalid class-typed assignments are rejected. The
constructor name `dhaw` remains supported for compatibility; prefer `dhis`.
# Error Handling
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Error Handling in Soplang [#error-handling-in-soplang]
An uncaught runtime error, such as division by zero, stops the program. Use
`tijaabi` and `qabo` to catch an error and continue execution.
tijaabi and qabo – Try / Catch [#tijaabi-and-qabo--try--catch]
Place code that may fail inside a `tijaabi` block. If an error occurs, execution
transfers to `qabo`. The variable in `qabo (...)` receives the error message
as a string (`qoraal`).
* A `tijaabi` block needs `qabo`, `dhammee`, or both.
* If no error occurs, the `qabo` block is skipped.
* Try blocks can be nested. The nearest enclosing `qabo` catches an error.
`tijaabi` catches errors from built-ins, methods, callbacks, and division by zero. A callback error stops iteration and propagates to the nearest `qabo`. Lexer, parser, and analysis errors occur before execution and cannot be caught this way.
Raising errors and cleanup [#raising-errors-and-cleanup]
`tuur` raises a string or a structured `khalad` value. The first `qabo`
binding receives the message; an optional second binding receives the error
with `.fariin`, `.summad`, and `.sabab` fields. `dhammee` runs when the
protected block exits, including after an error or return.
The `khalad(fariin, summad?, sabab?)` constructor creates an error value
without raising it. Errors can be chained through `.sabab`. An uncaught error
includes a source location and call trace. See the
[language reference](https://github.com/soplang/soplang/blob/v3.6.0/docs/language/keywords.md#structured-errors)
for rethrowing and cleanup rules.
Error Messages [#error-messages]
Soplang's diagnostic output is in Somali. The following examples preserve
the actual message format:
```text
Khalad : [] safka , tiirka
--> ::
```
For example, reassigning a `madoor` constant produces:
```text
Khalad nooc: Ma bedeli kartid qiimaha doorsamaha madoor 'luqad' [E020] safka 2, tiirka 1
--> luqad.sop:2:1
2 │ luqad = "English"
│ ^^^^^
└─ Doorsamaha madoor ma beddeli karaan qiimahooda. Isticmaal 'door' haddii aad rabto mid beddeli kara.
```
Diagnostic categories (`` in the format above) identify the phase:
| Category | Meaning |
| ----------- | ------------------------------------------------------------------ |
| `ereyayn` | Lexing: an unknown character, unclosed string, or unclosed comment |
| `naxwe` | Parsing: invalid syntax, such as a missing `)` or `}` |
| `nooc` | A type or declaration error |
| `fulin` | A runtime error, such as division by zero |
| `soo-dejin` | An import error, such as a missing file named by `keen` |
Disable diagnostic colors with `--no-color` or `NO_COLOR=1`.
Error Codes [#error-codes]
Some diagnostics include a short code:
| Code | Meaning |
| ------ | ------------------------------------------------------------------ |
| `E001` | Unexpected character |
| `E002` | Unclosed string |
| `E003` | Unclosed `/* */` comment |
| `E020` | Redeclaration or reassignment of a `madoor` constant |
| `E021` | Missing item, such as an imported file |
| `E022` | Type mismatch in an assignment, function argument, or return value |
Source Context and Exit Status [#source-context-and-exit-status]
Uncaught failures write Somali diagnostics to stderr and exit with status 1.
Source diagnostics include the source file, line, column, source line and caret.
Infrastructure errors without a source location omit line and column numbers. Columns
count Unicode scalar values; caret spacing accounts for tabs, combining marks
and wide characters. Imported files retain their own source context. LLVM-built
executables retain relevant source lines even when the original files are gone.
Caught errors are message strings, not structured error objects or stack traces.
`fasax` remains a compatible try spelling; new examples use `tijaabi`.
CLI argument errors, such as unknown flags or missing values, use Somali
explanations and exit with status 2. `--help` and `--version` exit with status 0.
File and tool failures retain exit status 1.
Set `SOPLANG_ERROR_DETAILS=1` to include original external tool or OS messages
under `Faahfaahin farsamo:` on stderr. These optional details can be English.
They are separate from the primary diagnostic and never become part of the
message string received by `qabo`. The setting also works in LLVM-built
executables; their normal runtime error messages remain Somali.
# Modules
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Modules in Soplang [#modules-in-soplang]
Split larger programs into multiple `.sop` files. `keen` imports another file
and makes its functions, variables, and classes available to the importing program.
Importing a File – keen [#importing-a-file--keen]
Write `keen` followed by a quoted file path:
```bash
soplang main.sop
```
How keen Works [#how-keen-works]
* **Relative paths** are resolved from the directory of the file containing `keen`, rather than the terminal's working directory. Imports therefore work whether you run `soplang main.sop` or `soplang project/main.sop`.
* **Top-level definitions**, including functions, variables, constants, and classes, become available in the importing program.
* **Top-level code executes** when the file is imported, including calls such as `qor(...)`.
* **Each file is imported once**, including when it is referenced more than once or participates in circular imports.
* A missing file produces an import diagnostic in Somali:
```text
Khalad soo-dejin: Faylka 'nope.sop' ma helin [E021] safka 1, tiirka 1
--> main.sop:1:1
1 │ keen "nope.sop"
│ ^^^^
└─ Hubi in magaca faylka iyo jidka ay sax yihiin.
```
Tips [#tips]
* Put `keen` statements at the beginning of a file so its dependencies are easy to find.
* Give helper files descriptive names, such as `utils/xisaab.sop` or `_math_lib.sop`.
* Avoid defining the same name in different imported files. Colliding names can produce a redeclaration error.
# CLI and REPL
CLI commands and diagnostics [#cli-commands-and-diagnostics]
The Soplang 3.6 CLI accepts English and Somali names for the same
actions. Each top-level name also accepts a `--` prefix: `build`, `--build`,
`dhis`, and `--dhis` all use one build path. These command aliases do not
change Soplang source-language keywords.
Commands [#commands]
| English | Somali | Action |
| --------------- | -------------- | -------------------------------------- |
| `init` | `abuur` | Create a project. |
| `run` | `fuli` | Run one source file or a project. |
| `build` | `dhis` | Build executable programs. |
| `check` | `hubi` | Check source without running it. |
| `fmt` | `habee` | Format source. |
| `test` | `tijaabi` | Run tests. |
| `doc` | `duk` | Generate Markdown API documentation. |
| `debug` | `baar` | Debug one program. |
| `profile` | `cabbir` | Measure execution. |
| `add` | `kudar` | Add a dependency. |
| `remove` | `saar` | Remove a dependency. |
| `update` | `cusboonaysii` | Update locked dependencies. |
| `publish` | `daabac` | Publish the current package. |
| `data generate` | `xog abuur` | Generate or check a schema client. |
| `repl` | `isdhexgal` | Open the interactive shell. |
| `eval` | `qiimee` | Run a supplied source snippet. |
| `example` | `tusaale` | Run a numbered bundled example. |
| `inspect` | `eeg` | Display AST or HIR without executing. |
| `help` | `caawimo` | Show general or command-specific help. |
| `version` | `nooc` | Show the Soplang software version. |
| `lsp` | `lsp` | Start the editor protocol server. |
Only `doc` and `duk` name the documentation command; `docs` is not an alias.
The `--` prefix applies to a **top-level action**, not to ordinary arguments:
`soplang --dhis hello.sop` builds just like `soplang dhis hello.sop`.
The separate `--` token before arguments passes them to a running program:
`soplang fuli app.sop -- first second`.
```sh
soplang # interactive command browser in a terminal
soplang repl # interactive Soplang shell
soplang program.sop # quick file execution
soplang fuli program.sop # equivalent explicit action
soplang qiimee 'qor("Salaan!")'
soplang dhis program.sop # writes dhis/program (program.exe on Windows)
soplang hubi program.sop
soplang eeg program.sop --hir
soplang caawimo dhis
```
`build` with no path builds the current project. One or more `.sop` paths build
one executable per file in `dhis/`; each output takes its source stem. If two
input files have the same stem, the command fails before building. A project
build uses the `magac` in `soplang.toml`. Use `--name` or `--magac` for a single
build's executable name. `-o`/`--output` remains available when an exact output
path is needed. `keen` imports combine several source files into **one**
program; passing several files to `build` makes separate programs.
With no arguments in a terminal, Soplang opens a command browser. Up and Down
browse commands or options, Tab completes them, and the current choice shows
its description. Select a command to see its arguments and options, then press
Enter to run it. `soplang repl` or `soplang isdhexgal` starts the Soplang shell
directly. When input is piped, bare `soplang` keeps opening the REPL.
`-i`/`--interactive`/`--isdhexgal` continues in the REPL after running a file
or example. Use `/caawi` for REPL commands and `/bixi` to exit. AST and HIR
dumps retain compiler notation.
Options [#options]
| English | Somali | Applies to |
| ------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `--help`, `-h` | `--caawimo` | General and command help. |
| `--version`, `-V` | `--nooc` | Software version. |
| `--strict` | `--adag` | Run, build, check, debug and source evaluation. |
| `--offline` | `--kayd-keliya` | Locked, verified cached **package dependencies** only; does not disable network APIs in a running program. |
| `--no-color` | `--midab-dami` | Diagnostic color. |
| `--name` | `--magac` | Project creation and a single build's executable name. |
| `--opt-level`, `-O` | `--heer-hagaajin` | Build optimization level `0..3`. |
| `--quiet`, `-q` | `--aamus` | Build success messages. |
| `--output`, `-o` | `--natiijo` | Exact build output path; documentation and data generation also accept an output path. |
| `--lib` | `--maktabad` | Create a library project. |
| `--write` | `--qor` | Format files in place. |
| `--private` | `--gaar` | Include private names in generated documentation. |
| `--break` | `--hakad` | Debugger breakpoint at `[FILE:]LINE`; existing `--jebi` remains. |
| `--continue` | `--soco` | Continue to a breakpoint when debugging. |
| `--parallel` | `--barbar` | Run tests with an automatic worker count; existing `--wada` remains. |
| `--filter`, `--index` | `--shaandhe`, `--lambarka` | Select tests by name or zero-based index. |
| `--workers`, `--coverage`, `--report` | `--shaqaale`, `--dabool`, `--warbixin` | Set test workers, coverage, and report path. |
`init`, `debug`, and `data generate` have further options under their own
`--help` screens. Existing invocations such as `soplang -c CODE`, `-f FILE`,
`-e NUMBER`, `--ast FILE`, `--hir FILE`, `--ku-dar ... --qeexid ...`,
`--ka-saar`, `--cusbooneysii`, and `--daabac` remain supported.
Help and version output go to stdout and exit successfully. Invalid CLI
arguments go to stderr with exit status 2. Compilation and unhandled runtime
failures retain exit status 1. The localization does not change program output
or the language's keywords and compatibility names.
Error explanations [#error-explanations]
A missing source file produces a contextual message such as:
```text
Khalad fulin: Faylka 'magac.sop' lama helin.
```
Permission, invalid UTF-8, directory, storage, and tool failures receive their
own explanations where the operating system provides a recognizable cause.
Unknown causes receive a general Somali explanation. Infrastructure errors
without a source location omit line and column numbers.
Source errors still retain their original file, one-based line and column,
error code when available, source text, and caret. Tabs and Unicode display
width continue to determine caret spacing. These locations describe source
characters rather than UTF-8 byte offsets.
Technical details [#technical-details]
Set `SOPLANG_ERROR_DETAILS=1` to include original OS, compiler, or linker
messages under `Faahfaahin farsamo:` on stderr:
```sh
SOPLANG_ERROR_DETAILS=1 soplang --build program.sop -o program
```
In PowerShell:
```powershell
$env:SOPLANG_ERROR_DETAILS = '1'
soplang --build program.sop -o program
Remove-Item Env:SOPLANG_ERROR_DETAILS
```
The additional text can be English. Tool names, paths, versions, platform
identifiers, and error codes remain literal in both modes. Keep these details
when reporting a compiler or package problem. Unset the variable or give it
another value to return to normal explanations.
Caught errors retain their Somali primary message regardless of this setting;
the troubleshooting details do not become part of the value supplied to
`qabo`.
`NO_COLOR=1` or `--no-color` disables diagnostic color. Neither setting
translates text printed by the Soplang program itself. Third-party panics and
failures before Soplang starts are outside normal diagnostic handling.
Create a project [#create-a-project]
`soplang init [directory] [--lib] [--name name]` creates a manifest and a starter.
Applications start in `main.sop`, libraries in `lib.sop`. See
[packages](https://github.com/soplang/soplang/blob/v3.6.0/docs/language/packages.md#create-a-project). `soplang init --help` explains the
options in Somali. Existing manifests and starters are preserved.
Git packages and offline builds [#git-packages-and-offline-builds]
Add a repository dependency with `soplang --ku-dar name --qeexid source`.
`source` may be `github.com/team/project@tag`, a `git+URL#revision`, or a local
path. `--cusbooneysii` updates the lock explicitly; `--ka-saar name` removes a
dependency. `--offline` uses an existing lock and verified cache without a fetch.
See [packages](https://github.com/soplang/soplang/blob/v3.6.0/docs/language/packages.md) for selectors, graph constraints and cache behavior.
# Migrating to Soplang 3
import SoplangCodeWindow from "../../components/SoplangCodeWindow";
Soplang 3 establishes the Rust compiler, the Cranelift JIT, and the LLVM AOT backend as the supported implementation. This release also makes runtime behavior stricter and establishes the public vocabulary and compatible naming improvements.
Vocabulary [#vocabulary]
Update programs that still use names from earlier Soplang 2 releases or documentation:
| Earlier spelling | Soplang 3 |
| ---------------- | --------- |
| `fasalka` | `qaab` |
| `ka_dhaxal` | `dhaxal` |
| `ka_keen` | `keen` |
| `isku_day` | `tijaabi` |
| `howl` | `hawl` |
| `soo_celi` | `celi` |
| `bandhig` | `qor` |
| `akhri` | `gelin` |
| `ku_celi` | `kuceli` |
| `inta_ay` | `intay` |
| `sii_wad` | `soco` |
| `tiro` | `abn` |
| `liis` | `teed` |
| `shey` | `walax` |
| `labadaran` | `bool` |
| `waxba` | `maran` |
| `kudhow` | `xul` |
| `raadso` | `raadi` |
| `null` | `maran` |
`null` remains accepted as a compatibility spelling. New code should use `maran`.
Calls and constructors [#calls-and-constructors]
Functions, closures, methods, built-ins, and constructors now enforce their argument counts. Known argument-count mismatches are rejected during analysis. Dynamic calls with invalid argument counts report catchable runtime errors.
Constructor arguments are also checked against the inherited or local `dhis()` or legacy `dhaw()` definition.
Numeric conversion and ranges [#numeric-conversion-and-ranges]
`abn()` and `jajab()` accept trimmed numeric strings:
`abn()` rejects decimal strings such as `"3.5"`. `baaxad()` accepts integer arguments only and reports an error when its step is zero.
Indexing [#indexing]
String indexes count Unicode characters. Lists and strings support negative indexes from the end. An out-of-range read returns `maran`; an out-of-range list write reports a catchable error.
Objects now accept computed string keys:
Logical operators [#logical-operators]
`&&` and `||` now short circuit. The right expression runs only when its result is needed.
Semicolons [#semicolons]
Semicolons are optional and supported consistently. Existing newline-oriented source remains valid.
New standard library APIs [#new-standard-library-apis]
* Numbers: `duub`, `sugan`, `yar`, `weyn`, `jibbaar`, `xidid`
* Lists: `geli`, `midee`, `saar`, `hore`, `dambe`, `ururi`, `dhammaan`, `qaar`
* Objects: `hel`, `dhig`, `saar`, `midee`, `furayaal`, `qiimayaal`, `lammaanayaal`, plus bracket access
* Strings: `dherer`, `masax`, `tiri`, `kuceli`, `raadi`, `xiriiri`, `weynee`, `yaree`, `beddel`
See the [language reference](/docs/14_keywords-reference) for signatures and examples.
Shared collection methods and canonical names [#shared-collection-methods-and-canonical-names]
New code may use the following names while earlier spellings remain supported:
| Earlier API | Canonical API |
| ---------------------------- | ------------------ |
| Constructor `dhaw()` | `dhis()` |
| Try block `fasax` | `tijaabi` |
| Exponentiation `awood(a, b)` | `jibbaar(a, b)` |
| List `muuji(item)` | `raadi(item)` |
| String `dhamaad(sub)` | `dhammaad(sub)` |
| String `masax_dhamaad()` | `masax_dhammaad()` |
| List `kasaar()` | `saar()` |
| List `ka_saar(index)` | `saar(index)` |
| Object `ka_qaad(key)` | `saar(key)` |
Lists and strings now support `hel(index, default?)`. Lists also support
`dhig(index, value)`, and objects support `dherer()` in addition to the global
length function. Existing `leeyahay`, `nuqul`, and `nadiifi` methods keep their
behavior. See the [shared operation contracts](/docs/14_keywords-reference#shared-collection-operations).
A missing read returns the supplied default or `maran`; an entry storing
`maran` is still present and does not select the default. List removal rejects
invalid positions and popping an empty list; object removal of a missing key
returns `maran`. Legacy `tir(key)` still returns the object.
The `tijaabi` spelling does not become globally reserved. Existing functions,
variables, or properties with that name continue to parse.
Constructor lookup walks classes from child to parent, trying `dhis` before
`dhaw` within each class. A child's legacy constructor therefore still takes
precedence over an ancestor's canonical constructor. Explicit method calls
prefer the requested spelling within each class and then try its counterpart,
including calls through `waalid`.
No old spelling is scheduled for removal. `kudar` retains its earlier mutation
and copying behavior. Prefer the explicit operations described below.
Short paired names and contextual branches [#short-paired-names-and-contextual-branches]
| Earlier spelling | Preferred spelling |
| --------------------------------- | -------------------------- |
| List `koowaad()` | `hore()` |
| List `ugu_dambeeya()` | `dambe()` |
| `ugu_yar(...)` | `yar(...)` |
| `ugu_weyn(...)` | `weyn(...)` |
| `haddii_kale (condition) { ... }` | `kale (condition) { ... }` |
| `ugudambeyn { ... }` | `kale { ... }` |
First/last list methods return `maran` for empty lists. Numeric selection keeps
its existing argument validation and result types. Every earlier spelling in
this table remains supported.
`kale (condition) { ... }` adds a conditional branch after `haddii`, while
`kale { ... }` supplies a fallback. Switches also accept `kale { ... }` as the
default case. Canonical and compatibility branches may be mixed. `kale` remains
an identifier elsewhere, including function declarations, arguments, variables,
and properties. An ordinary `kale(...)` call after an if statement is preserved
when it is not followed by a branch block.
Insertion, combination, and text operations [#insertion-combination-and-text-operations]
* `list.geli(value)` appends one item, even when the value is a list.
`list.geli(index, value)` keeps indexed insertion. Both mutate the receiver.
* `list.midee(other_list)` and `object.midee(other_object)` return new shallow
collections, leaving both inputs unchanged. Object keys on the right win.
* `separator.xiriiri(list)` joins string representations. Legacy `kudar`
remains supported on all three receivers with its earlier contracts.
| Earlier spelling | Preferred call |
| -------------------------------------- | --------------------------------------------- |
| `isku_gee(func, initial)` | `ururi(func, initial)` |
| `xarfaha_waaweyn()`, `xarafaha_weyn()` | `weynee()` |
| `xarfaha_yaryar()` | `yaree()` |
| `masax_bilow()` | `masax("hore")` |
| `masax_dhamaad()`, `masax_dhammaad()` | `masax("dambe")` |
| `raadi_dambe(sub)` | `raadi(sub, "dambe")` |
| `beddel_dhammaan(old, new)` | `beddel(old, new, maran)` |
| String `ku_celi(count)` | `kuceli(count)` |
| `dhammeystir(value)` | `duub(value)` |
| `fure()`, `qiime()`, `lamaane()` | `furayaal()`, `qiimayaal()`, `lammaanayaal()` |
`masax()` still trims both ends; `raadi(sub)` still searches first. Direction
arguments accept only `"hore"` and `"dambe"`. `beddel(old, new)` still replaces
one match. Its optional third argument is a nonnegative integer limit or
`maran` for all matches. Replacement and repetition reject fractional and
negative counts. Numeric loops still use `kuceli`; the parser also accepts
`.kuceli(count)` after a dot.
`ururi` is a general left fold. Map, filter, fold, every, and some now iterate
a shallow snapshot, allowing callbacks to change the original list. Callback
errors stop iteration and propagate to `qabo`, including errors from map and
filter that previously could be lost. Invalid callbacks are rejected even on
empty lists. Every/some continue to short circuit.
Object key/value/pair lists follow sorted-key order. `duub` rounds to the
nearest integer with ties away from zero. `xidid` continues to mean square root.
All additions belong to Soplang 3; no version 4 transition is planned.
Collection consistency and corrected global updates [#collection-consistency-and-corrected-global-updates]
Lists now accept `jar()` and `jar(start)` alongside `jar(start, end)`. Lists and
strings both require integer bounds; fractional values previously truncated by
slicing now report a catchable error. Negative bounds count from the end and
bounds are clamped. The end is excluded. Reversed or equal bounds return an
empty result; reversed string bounds no longer panic. List slices are shallow
copies and neither receiver is modified.
Strings add `hore()` and `dambe()` for first/last Unicode characters, returning
`maran` for empty strings, matching list endpoint behavior. Lists add
`tiri(value)` using existing list equality rules. String `tiri(sub)` still counts
non-overlapping substring matches and rejects an empty substring. Search misses
continue to return `maran` on lists and `-1` on strings for compatibility.
Global writes from functions, methods, and callbacks are now visible on the next
top-level read, including replacements of collection and callable values. Local
variables and parameters still shadow globals. Top-level numeric loop indexes
are shared with functions, and updates from the loop body feed the next increment.
REPL snippets observe the same current global values.
Writes to typed globals inside functions now enforce type and class checks.
Rejected assignments and failed right-hand expressions preserve the previous
global value. Accepted numeric values are converted to their annotated runtime
representation: integral floats become `abn` and integers become `jajab`.
Fractional floats remain invalid for integer annotations. This corrects stale
reads, invalid writes, and mismatched native numeric representations.
Source diagnostics [#source-diagnostics]
Errors now show Somali phase names (`ereyayn`, `naxwe`, `nooc`, `fulin`, and
`soo-dejin`) with the original file, line, column, source line, and caret.
Compiled LLVM executables retain the relevant source line for runtime errors;
`keen` imports retain their own file locations. Unclosed strings/comments point
to the opening delimiter. CLI/REPL expression echo preserves original columns.
Columns count Unicode scalar values, and the displayed caret accounts for tabs,
combining marks, and wide characters. `--no-color` and `NO_COLOR=1` produce plain
output. Uncaught failures exit with status 1 and write diagnostics to stderr.
Caught errors remain message strings. Unknown variable reads now report a
Somali error instead of silently producing `maran`.
See the [intentional error examples](https://github.com/soplang/soplang/blob/v3.0.0/examples/errors/README.md) for checked
examples of each diagnostic category.
# Soplang 3.6
Soplang 3.6 [#soplang-36]
Soplang 3.6.0 brings the work developed since the published 3.0.1 release into
one release. It retains Somali source syntax and supports both Cranelift JIT
execution and LLVM native builds.
Language and runtime [#language-and-runtime]
* Tracing garbage collection, isolated execution contexts, catchable structured
errors, `tuur`, guaranteed `dhammee` cleanup, stack traces, and precise source
locations.
* Escaped, raw, multiline, and interpolated strings; value formatting; direct
calls of returned and stored functions; default, variadic, and named arguments.
* Direct iteration and iterator protocols, immutable tuples, sets, byte arrays,
optional and union annotations, and typed collections. Text, list, object,
and numeric libraries include the operations documented in [language reference](https://github.com/soplang/soplang/tree/v3.6.0/docs/language/).
Files, networking, and applications [#files-networking-and-applications]
* Text and binary files, directories, paths, JSON, CSV, regular expressions,
timestamps, environment variables, arguments, and child processes.
* HTTP and HTTPS clients, DNS, TCP, UDP, WebSocket clients, and HTTP servers.
* Modules with explicit exports and cached initialization; Git and local path
dependencies pinned by a root lock file.
* A bundled `web` module with routes, middleware, request parsing, responses,
templates, static files, cookies, sessions, TLS, and an application test client.
* `schema.sop` and generated data clients for SQLite, PostgreSQL,
CockroachDB, MySQL, MariaDB, MongoDB, and SQL Server. The data API supports
validation, typed filters, pools, transactions, and additive migrations.
Concurrency [#concurrency]
Tasks use `sug(task)` and channels to coordinate asynchronous file, network,
and timer work. HTTP servers handle multiple requests, stream bounded bodies,
support WebSocket connections, and drain active work during shutdown. Request
failures remain isolated from the server. See the
[concurrency model](https://github.com/soplang/soplang/blob/v3.6.0/docs/architecture/CONCURRENCY.md) and
[HTTP server API](https://github.com/soplang/soplang/blob/v3.6.0/docs/language/http-server.md) for exact behavior and limits.
Tools and packages [#tools-and-packages]
The CLI accepts English and Somali command names, including `run`/`fuli`,
`build`/`dhis`, `check`/`hubi`, `fmt`/`habee`, `test`/`tijaabi`, and
`doc`/`duk`. Project initialization, package management, source debugging,
profiling, documentation generation, formatting, and source coverage are
available. The language server and [VS Code extension](/docs/22_vscode-extension) provide editing support.
Installed native packages include the compiler, LLVM object generation, a
platform linker, and the Soplang runtime needed for `soplang build`. Building a Soplang program
does not require a separate Rust or Clang installation. Building Soplang itself
from source still requires its Rust and native build dependencies. The generated
executable runs without Soplang or its source files beside it and targets the
same operating system and architecture as the compiler package.
Keep the package's `lib/soplang` directory beside its executable. See
[installation](/docs/00_installation) for layouts and platform requirements.
Read the [Soplang 3.6 release article](https://www.somast.so/en/blog/soplang-3-6-release) for an introduction to these additions and the [verification record](https://github.com/soplang/soplang/blob/main/docs/testing/RELEASE_VERIFICATION_3_6.md) for platform checks.
Compatibility and limits [#compatibility-and-limits]
Existing 3.0 programs retain their syntax and aliases. Some new standard
library names have compatibility spellings; consult the linked language
references for their current canonical forms. Database servers, network
services, and TLS certificates remain external resources when an application
uses them. The data layer does not implement joins, relations, arbitrary SQL,
destructive migrations, or schema drift repair.
Detailed milestone references: [3.1](https://github.com/soplang/soplang/blob/v3.6.0/docs/releases/3.1.0.md), [3.2](https://github.com/soplang/soplang/blob/v3.6.0/docs/releases/3.2.0.md),
[3.3](https://github.com/soplang/soplang/blob/v3.6.0/docs/releases/3.3.0.md), [3.4](https://github.com/soplang/soplang/blob/v3.6.0/docs/releases/3.4.0.md), and [3.5](https://github.com/soplang/soplang/blob/v3.6.0/docs/releases/3.5.0.md).
# VS Code extension
VS Code extension [#vs-code-extension]
The [Soplang extension](https://github.com/soplang/vsCodeLanguageSupport) adds
syntax highlighting, snippets, diagnostics, completion, navigation, formatting,
and Run, Build, and REPL commands. Its 3.6 update uses the installed Soplang
compiler's language server for current language and `schema.sop` analysis.
Install Soplang first [#install-soplang-first]
Install the [3.6 package for your platform](/downloads) on the same machine where
VS Code runs its workspace extension host. In SSH, WSL, and container workspaces,
that means the remote environment. Check the executable there:
```sh
soplang nooc
```
Set `soplang.compilerPath` in VS Code if the executable is not on `PATH`:
```json
{
"soplang.compilerPath": "/path/to/soplang"
}
```
The extension does not download the compiler. The official 3.6 packages include
the LLVM generator, linker, and runtime needed by the Build command; building a
Soplang program does not require a separate Rust or Clang installation.
What the editor provides [#what-the-editor-provides]
The installed compiler analyzes source without executing it. The editor uses
unsaved buffers for diagnostics and navigation. `schema.sop` gets its own
highlighting, snippet, completion, hover, formatting, and schema diagnostics.
Native definitions can open read-only source references from the installed
compiler. The Run and Build commands execute a saved source file in a terminal;
Open REPL starts `soplang isdhexgal`.
Syntax highlighting and snippets work without a compiler. When a 3.6 compiler
cannot be found, the extension can use its bundled 3.0 analysis server for
older source. Install Soplang 3.6 for current file, network, task, web, and data
API analysis. Workspace Trust is required to start the compiler or a custom
analysis server.
A source debugger and debug adapter are not included in the extension. See the
[extension support matrix](https://github.com/soplang/vsCodeLanguageSupport/blob/main/docs/SUPPORT.md)
for its exact limits and the [3.6 overview](/docs/21_soplang-3-6) for language
capabilities.
# FAQ
General [#general]
What is Soplang? [#what-is-soplang]
Soplang is the Somali programming language. Its keywords and built-ins are in Somali (`door`, `hawl`, `haddii`, `qor`, …), so Somali speakers can learn programming in their own language. It supports both dynamic (`door`) and static (`abn`, `qoraal`, …) typing.
How does Soplang run my code? [#how-does-soplang-run-my-code]
Soplang is implemented in Rust. `soplang fuli file.sop` runs a program with the Cranelift JIT. `soplang dhis file.sop -o app` builds a standalone native program using bundled LLVM, a platform linker, and the Soplang runtime. Official 3.6 packages do not require a separate Rust or Clang installation to run or build programs. See [CLI & REPL](/docs/19_cli-and-repl).
Is it open source? [#is-it-open-source]
Yes. Soplang is open source under the MIT License. The source is at [github.com/soplang/soplang](https://github.com/soplang/soplang).
Installation & Setup [#installation--setup]
How do I install Soplang? [#how-do-i-install-soplang]
Download a prebuilt release from the [downloads page](/downloads), build it from source with Cargo, or run it with Docker. See the [installation guide](/docs/00_installation).
What file extension does Soplang use? [#what-file-extension-does-soplang-use]
Use `.sop` for new programs. The CLI also accepts the compatible `.so` source extension.
Language Features [#language-features]
Does it support classes? [#does-it-support-classes]
Yes. Classes are defined with `qaab`, created with `cusub`, can inherit with `dhaxal`, and use `nafta` for the current instance. See [Classes](/docs/16_classes). There are no interfaces.
Can I handle errors? [#can-i-handle-errors]
Yes. Use `tuur` to raise an error, `tijaabi`/`qabo` to catch it, and `dhammee` for guaranteed cleanup. See [Error Handling](/docs/17_error-handling).
Can I split my program into multiple files? [#can-i-split-my-program-into-multiple-files]
Yes, with `keen "file.sop"`. See [Modules](/docs/18_modules).
Do I need semicolons? [#do-i-need-semicolons]
No. Semicolons are optional statement separators. Both `door x = 1` on its own line and `door x = 1; qor(x);` are valid.
Does Soplang have string interpolation? [#does-soplang-have-string-interpolation]
Yes. `qor(f"Da'da: {da}")` interpolates a value; `+` also joins strings.
Community & Support [#community--support]
Where can I get help? [#where-can-i-get-help]
Visit the [Discord](https://discord.gg/n296G4dd7x), or open an issue on [GitHub](https://github.com/soplang/soplang/issues).
# Soplang Documentation
**Soplang** (Somali Programming Language) is a free, open-source programming language whose keywords are Somali words: `qor` prints, `haddii` means *if*, and `hawl` defines a function. It was created by Sharafdin Yusuf, first released in October 2023, and is developed and maintained by [Somast](https://www.somast.so/).
These docs cover installation, language syntax, classes, modules, errors, and the 3.6 runtime. The [3.6 reference](/docs/21_soplang-3-6) covers files, networking, web servers, databases, tasks, and project tools.
These docs target **Soplang 3.6.0**, the Rust compiler with Cranelift JIT and LLVM standalone builds. See [Migrating to Soplang 3](/docs/20_migrating-to-v3) for compatibility and behavior changes.
Getting Started [#getting-started]
* [Installation](/docs/00_installation) - Learn how to install Soplang
* [Getting Started](/docs/00_getting-started) - Write your first Soplang program
Language Basics [#language-basics]
* [Syntax Basics](/docs/01_syntax-basics) - Learn the fundamentals
* [Variables](/docs/03_variables) - Working with variables
* [Data Types](/docs/09_data-types) - Understanding data types
* [Operators](/docs/05_operators) - Using operators
* [Functions](/docs/08_functions) - Defining and using functions
Advanced Topics [#advanced-topics]
* [Arrays](/docs/12_arrays) - Working with arrays
* [Objects](/docs/13_objects) - Working with objects
* [Loops](/docs/07_loops) - Control flow with loops
* [Conditional Statements](/docs/06_conditional-statements) - Making decisions
* [Classes](/docs/16_classes) - Object-oriented programming with `qaab`
* [Error Handling](/docs/17_error-handling) - Catching errors with `tijaabi` and `qabo`
* [Modules](/docs/18_modules) - Splitting code across files with `keen`
Reference [#reference]
* [Keywords Reference](/docs/14_keywords-reference) - Core keywords and methods
* [Built-in Functions](/docs/15_built-in-functions) - Available built-in functions
* [CLI & REPL](/docs/19_cli-and-repl) - Running, building, and the interactive shell
* [Soplang 3.6](/docs/21_soplang-3-6) - New capabilities and reference links
* [VS Code extension](/docs/22_vscode-extension) - Editor setup, schema files, and compiler tasks
* [FAQ](/docs/faq) - Frequently asked questions