Soplang Logo
Soplang

Soplang 3 Language Reference

The Soplang 3.6 reference: Somali keywords, types, functions, collection methods, classes, closures and compatibility names.

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 also covers the 3.6 file, network, task, web, and data APIs.

The terminology review 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

KeywordMeaningEnglish EquivalentExample
doorDynamic variable declarationvar/letdoor magac = "Sharafdin"
madoorConstant variable declarationconstmadoor PI = 3.14159
abnInteger typeintabn da = 25
jajabBinary floating-point typefloat/doublejajab qiimo = 3.14
qoraalString typestringqoraal magac = "Sharafdin"
boolBoolean typeboolbool waaRun = run
walaxObject typeobjectwalax person = { name: "Sharafdin" }
teedList/array typearrayteed numbers = [1, 2, 3]
xirmoImmutable tuple typetuplexirmo row = xirmo(1, "Ayaan")
ururSet typeseturur items = urur(1, 2)
maranNull valuenulldoor a = maran

Control Flow Keywords

KeywordMeaningEnglish EquivalentExample
haddiiIf statementifhaddii (x > 10) { qor("Weyn") }
kaleElse if statementelse ifkale (x == 10) { qor("Dhexe") }
kaleElse/default statementelsekale { qor("Yar") }
dooroSwitch statementswitchdooro (x) { xaalad 1 { qor("Hal") } }
xaaladCase clausecasexaalad "A" { qor("Case A") }
kuceliFor loopforkuceli (i 1 ilaa 5) { qor(i) }
ilaaLoop range endtokuceli (i 1 ilaa 5) { qor(i) }
::Loop step/increment amount (optional, follows the range)stepkuceli (i 1 ilaa 10 :: 2) { qor(i) } — loops from 1 to 10, incrementing i by 2 each time
intayWhile loopwhileintay (x < 5) { qor(x) }
joojiBreak statementbreakhaddii (x == 3) { jooji }
socoContinue statementcontinuehaddii (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 {.

reference-1.sop
abn da = 21
haddii (da < 18) {
  qor("Ilmo")
} kale (da < 60) {
  qor("Qof weyn")
} kale {
  qor("Waayeel")
}

Function Keywords

KeywordMeaningEnglish EquivalentExample
hawlFunction declarationfunctionhawl isuGee(a, b) { celi a + b }
celiReturn statementreturnceli x * 2

Special Values

Somali ValueEnglish EquivalentDescriptionExample
runtrueBoolean true valuehaddii (run) { ... }
beenfalseBoolean false valuehaddii (!been) { ... }
marannullEmpty/null valuedoor 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

Somali TypeEnglish EquivalentDescriptionExample
abnintInteger numbersabn age = 25
jajabfloat/doubleBinary floating-point numbersjajab pi = 3.14
qoraalstringText valuesqoraal name = "Ahmed"
boolbooleanTruth valuesbool isValid = run
teedlist/arrayList of itemsteed numbers = [1, 2, 3]
walaxobjectKey-value pairswalax 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

Somali OperatorEnglish EquivalentDescriptionExample
++Additionx = a + b
--Subtractionx = a - b
**Multiplicationx = a * b
//Divisionx = a / b
%%Modulox = a % b
====Equal tohaddii (a == b) {...}
!=!=Not equal tohaddii (a != b) {...}
>>Greater thanhaddii (a > b) {...}
<<Less thanhaddii (a < b) {...}
>=>=Greater than or equal tohaddii (a >= b) {...}
<=<=Less than or equal tohaddii (a <= b) {...}
&&&&Logical ANDhaddii (a && b) {...}
||||Logical ORhaddii (a || b) {...}
!!Logical NOThaddii (!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

FunctionMeaningEnglish EquivalentExample
qorPrint to consoleprintqor("Salaan, Adduunka!")
gelinRead input from userinputdoor magac = gelin("Magacaaga geli: ")
noocGet type of variabletypeofqor(nooc(magac))
abnConvert value to an integer (also the int type keyword above)intdoor n = abn("5")
jajabConvert a number or numeric string to floating pointfloatdoor n = jajab("3.5")
qoraalConvert to stringstrdoor s = qoraal(25)
boolConvert to booleanbooldoor b = bool(1)
teedCreate a listlist/arraydoor list = teed(1, 2, 3)
walaxCreate an objectobject/dictdoor obj = walax("name", "Ali", "age", 25)
dajiRound down to integerMath.floor()door n = daji(4.7)
korRound up to integerMath.ceil()door n = kor(4.2)
dhererCount list items, object keys, or string characterslen()/.lengthdoor n = dherer(qoraal)
xulGet random valuerandom()door n = xul(1, 6)
baaxadCreate an integer rangerange()door n = baaxad(1, 5)
duubRound to the nearest integerround()door n = duub(4.6)
suganGet the absolute valueabs()door n = sugan(-5)
yarGet the smallest numeric argumentmin()door n = yar(4, 2, 8)
weynGet the largest numeric argumentmax()door n = weyn(4, 2, 8)
jibbaarRaise a number to a powerpow()door n = jibbaar(2, 3)
xididCalculate a square rootsqrt()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() 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:

reference-2.sop
// baaxad(stop): from 0 through stop - 1
qor(baaxad(5))  // [0, 1, 2, 3, 4]

// baaxad(start, stop): from start through stop - 1
qor(baaxad(2, 6))  // [2, 3, 4, 5]

// baaxad(start, stop, step): stop is excluded; increment by step
qor(baaxad(1, 10, 2))  // [1, 3, 5, 7, 9]

baaxad accepts integers only. A zero step reports an error that can be caught with tijaabi and qabo.

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.
reference-3.sop
door tirooyin = [10, 20, 30]
door qof = { magac: "Ayaan", da: 25 }
qor(tirooyin.hel(-1))
qor(qof.dherer())
tirooyin.dhig(0, 15)
qof.dhig("da", 26)
qor(tirooyin.saar())
qor(qof.saar("da"))

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

MethodEnglish EquivalentDescriptionExample
dherer()length()Get list lengthnumbers.dherer()
hel(index, default?)get()Read by index or return a defaultnumbers.hel(-1, maran)
dhig(index, value)indexed assignmentReplace an existing item and return the listnumbers.dhig(0, 5)
geli(item)push() or append()Add item to the original listnumbers.geli(5)
saar()pop()Remove and return last itemdoor last = numbers.saar()
midee(teed)concat()Concatenate listsdoor all = list1.midee(list2)
leeyahay(x)contains()/includes()Check if item existshaddii (list.leeyahay(x)) {...}
nuqul()copy()Create a shallow copydoor copy = list.nuqul()
nadiifi()clear()Remove all items from the original listlist.nadiifi()
rog()reverse()Reverse the original listlist.rog()
habee()sort()Sort the original list in ascending orderlist.habee()
jar(start?, end?)slice(a, b)Return a new list; start included, end excludeddoor subset = numbers.jar(1, 3)
aaddin(func)map(func)Transform items with functiondoor doubled = nums.aaddin(hawl(x) { celi x * 2 })
shaandhee(func)filter(func)Filter items with functiondoor evens = nums.shaandhee(hawl(x) { celi x % 2 == 0 })
raadi(item)indexOf(item)Find index of itemdoor idx = nums.raadi(5)
tiri(value)count()Count equal list itemsnumbers.tiri(5)
geli(index, item)insert(index, item)Insert into the original listnumbers.geli(1, 5)
saar(index)remove(index)Remove and return an indexed itemdoor item = numbers.saar(1)
hore()first()Return first item or marandoor item = numbers.hore()
dambe()last()Return last item or marandoor item = numbers.dambe()
ururi(func, bilow)reduce(func, initial)Fold with an arbitrary callback, not only additionnums.ururi(hawl(a, b) { celi a + b }, 0)
dhammaan(func)every(func)Test whether every item matchesnums.dhammaan(hawl(x) { celi x > 0 })
qaar(func)some(func)Test whether any item matchesnums.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

MethodEnglish EquivalentDescriptionExample
dherer()length()Count keysobj.dherer()
furayaal()keys()Get all keysdoor keys = obj.furayaal()
qiimayaal()values()Get all valuesdoor values = obj.qiimayaal()
lammaanayaal()entries()Get key-value pairsdoor pairs = obj.lammaanayaal()
leeyahay(x)hasOwnProperty()Check if key existshaddii (obj.leeyahay("name")) {...}
midee(obj)merge()/assign()Return a merged copydoor merged = obj1.midee(obj2)
nuqul()copy()Create a shallow copydoor copy = obj.nuqul()
nadiifi()clear()Remove all original propertiesobj.nadiifi()
hel(key, default?)get()Get a key or optional defaultobj.hel("name", "Unknown")
dhig(key, value)set()Set a computed keyobj.dhig("name", "Ali")
saar(key)remove()Remove and return a valuedoor 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

MethodEnglish EquivalentDescriptionExample
hore()first characterFirst Unicode character or marantext.hore()
dambe()last characterLast Unicode character or marantext.dambe()
hel(index, default?)character lookupRead a Unicode character or return a defaulttext.hel(-1, "")
qeybi(xad)split()Split string by delimiterdoor parts = text.qeybi(",")
leeyahay(sub)includes()Check if string contains substringhaddii (text.leeyahay("search")) {...}
dhammaad(sub)endsWith()Check if string ends with substringhaddii (text.dhammaad("ing")) {...}
bilow(sub)startsWith()Check if string starts with substringhaddii (text.bilow("http")) {...}
beddel(x, y, count?)replace()Replace first match, a limited count, or all with marandoor new = text.beddel("old", "new")
xiriiri(teed)join()Join string representations with separatordoor text = ", ".xiriiri(names)
jar(start?, end?)slice()Slice by character positiondoor sub = text.jar(0, 3)
weynee()toUpperCase()Convert string to uppercasedoor n = q.weynee()
yaree()toLowerCase()Convert string to lowercasedoor n = q.yaree()
masax(direction?)trim()Trim both ends, or "hore"/"dambe"door n = q.masax()
raadi(sub, direction?)indexOf()Find first/last character indexdoor n = q.raadi("pro")
dherer()lengthCount Unicode charactersdoor n = q.dherer()
tiri(sub)count()Count non-overlapping occurrencesdoor n = q.tiri("ab")
kuceli(n)repeat()Repeat the stringdoor 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)

Usage:

reference-4.sop
door q = "soplang"
door natiijo = q.weynee()
qor(natiijo)  // SOPLANG

yaree (Lowercase)

Usage:

reference-5.sop
door q = "SOPLANG"
door natiijo = q.yaree()
qor(natiijo)  // soplang

masax (Trim Whitespace)

Usage:

reference-6.sop
door q = "  soplang  "
door natiijo = q.masax()
qor(natiijo)  // soplang

raadi (Find Substring)

Usage:

reference-7.sop
door q = "soplang programming"
door natiijo = q.raadi("pro")
qor(natiijo)  // 8

beddel (Replace All)

Usage:

reference-8.sop
door q = "abaaba"
door natiijo = q.beddel("a", "x", maran)
qor(natiijo)  // xbxxbx

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)

Keyword / conceptMeaningEnglishExample
qaabClass definitionclassqaab Bisad { ... }
dhaxalInherit from parent classextendsqaab Bisad dhaxal Xayawaan { ... }
cusubCreate a new instancenewdoor b = cusub Bisad("Mia")
naftaCurrent instance (self)this / selfnafta.magac = magac
waalidCall a method on the parent classsuperceli waalid.cod()
dhisConstructor method (auto-called by cusub)constructorhawl dhis(magac) { nafta.magac = magac }

Class example:

reference-9.sop
qaab Xayawaan {
  hawl cod() {
      celi "xayawaan"
  }
}

qaab Bisad dhaxal Xayawaan {
  hawl dhis(magac) {
      nafta.magac = magac
  }
  hawl salaam() {
      qor("Salaan, " + nafta.magac)
  }
}

door bisad = cusub Bisad("Mia")
Bisad b = cusub Bisad("Mia")
bisad.salaam()
qor(bisad.magac)

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

KeywordMeaningEnglishExample
keenImport another .sop fileimportkeen "lib.sop"
tijaabiStart a protected try blocktrytijaabi { ... } qabo (e) { ... }
qaboCatch block with error variablecatchqabo (fariin) { qor(fariin) }
tuurRaise a string or structured errorraisetuur "Xog ma jirto"
dhammeeGuaranteed cleanupfinallytijaabi { ... } dhammee { ... }

Import example:

reference/_math_lib.sop
hawl laba() { celi 2 }
hawl afar() { celi 4 }
reference/main.sop
keen "_math_lib.sop"
qor(laba() + afar())   // 6

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:

reference-10.sop
tijaabi {
  qor(1 / 0)
} qabo (khalad) {
  qor("Qabtay: " + khalad)
}

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.

Compatibility spellings

Canonical APISupported 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 receivertir(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

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.

On this page