DictLib — Dictionary Library

Key/value storage for Plan9Basic programs. Dictionaries (associative arrays / maps) store and retrieve values using string keys instead of numeric indices. Three dictionary types are supported: numeric, string, and pointer.

CategoryCountDescription
Creation3dict#, sdict#, pdict#
Numeric Ops3dict_set#, dict_get, dict_getdef
String Ops3sdict_set#, sdict_get$, sdict_getdef$
Pointer Ops3pdict_set#, pdict_get#, pdict_getdef#
Generic Ops8dict_exists, dict_haskey, dict_count, dict_remove, dict_clear#, dict_type, dict_typename$, dict_key$
TypeCreate WithSetGetGet w/ Default
Numericdict#()dict_set#(d#, k$, n)dict_get(d#, k$)dict_getdef(d#, k$, def)
Stringsdict#()sdict_set#(d#, k$, s$)sdict_get$(d#, k$)sdict_getdef$(d#, k$, def$)
Pointerpdict#()pdict_set#(d#, k$, p#)pdict_get#(d#, k$)pdict_getdef#(d#, k$, def#)
ⓘ Note: All dictionaries use string keys. Values are typed per dictionary. Dictionaries are garbage-collected automatically.

Dictionary Creation

FunctionSignatureDescription
dict#()dict#@Create empty numeric dictionary
sdict#()sdict#@Create empty string dictionary
pdict#()pdict#@Create empty pointer dictionary
╯ plan9basic
' Numeric dictionary for ages
ages# = dict#()
dict_set#(ages#, "John", 25)
dict_set#(ages#, "Mary", 30)
println "John's age: "; dict_get(ages#, "John")

' String dictionary for capitals
capitals# = sdict#()
sdict_set#(capitals#, "France", "Paris")
sdict_set#(capitals#, "Germany", "Berlin")
println "Capital of France: "; sdict_get$(capitals#, "France")

' Pointer dictionary for objects
objects# = pdict#()
arr1# = dim#(10)
pdict_set#(objects#, "first", arr1#)

Numeric Dictionary Operations

FunctionSignatureDescription
dict_set#(d#, key$, value)dict_set#@#$nSet numeric value (creates or updates key)
dict_get(d#, key$)dict_get@#$Get numeric value (error if key missing)
dict_getdef(d#, key$, default)dict_getdef@#$nGet numeric value or default if key missing
╯ plan9basic
scores# = dict#()
dict_set#(scores#, "Player1", 100)
dict_set#(scores#, "Player2", 250)
dict_set#(scores#, "Player1", 150)  ' Updates Player1

println dict_get(scores#, "Player1")        ' 150
println dict_getdef(scores#, "Player3", 0)  ' 0 (default)
⚠ Warning: dict_get() raises an error if the key doesn’t exist. Use dict_getdef() or check with dict_exists() first.

String Dictionary Operations

FunctionSignatureDescription
sdict_set#(d#, key$, value$)sdict_set#@#$$Set string value (creates or updates key)
sdict_get$(d#, key$)sdict_get$@#$Get string value (error if key missing)
sdict_getdef$(d#, key$, default$)sdict_getdef$@#$$Get string value or default if key missing
╯ plan9basic
config# = sdict#()
sdict_set#(config#, "username", "admin")
sdict_set#(config#, "server", "localhost")

println sdict_get$(config#, "username")               ' admin
println sdict_getdef$(config#, "password", "none")    ' none (default)

Pointer Dictionary Operations

FunctionSignatureDescription
pdict_set#(d#, key$, value#)pdict_set#@#$#Set pointer value (creates or updates key)
pdict_get#(d#, key$)pdict_get#@#$Get pointer value (error if key missing)
pdict_getdef#(d#, key$, default#)pdict_getdef#@#$#Get pointer value or default if key missing
╯ plan9basic
arrays# = pdict#()
data1# = dim#(100)
data2# = sdim#(50)
pdict_set#(arrays#, "numbers", data1#)
pdict_set#(arrays#, "names", data2#)

retrieved# = pdict_get#(arrays#, "numbers")
ⓘ Note: Pointer dictionaries are useful for storing collections of arrays, other dictionaries, or GUI control references by name.

Generic Dictionary Operations

These functions work with any dictionary type (numeric, string, or pointer).

FunctionSignatureDescription
dict_exists(d#, key$)dict_exists@#$Check if key exists (returns 1 or 0)
dict_haskey(d#, key$)dict_haskey@#$Alias for dict_exists
dict_count(d#)dict_count@#Number of key/value pairs
dict_remove(d#, key$)dict_remove@#$Remove key (returns 1 if removed, 0 if not found)
dict_clear#(d#)dict_clear#@#Remove all entries (returns dict pointer)
dict_type(d#)dict_type@#Type code: 0=numeric, 1=string, 2=pointer
dict_typename$(d#)dict_typename$@#Type name: "numeric", "string", "pointer"
dict_key$(d#, index)dict_key$@#nKey at 0-based index
╯ plan9basic
ages# = dict#()
dict_set#(ages#, "John", 25)
dict_set#(ages#, "Mary", 30)
dict_set#(ages#, "Bob", 22)

' Check existence
if dict_exists(ages#, "John") = 1 then
    println "John found: "; dict_get(ages#, "John")
endif

' Count entries
println "Entries: "; dict_count(ages#)   ' 3

' Iterate all keys (0-based index!)
for i = 0 to dict_count(ages#) - 1
    key$ = dict_key$(ages#, i)
    println key$; ": "; dict_get(ages#, key$)
next

' Remove and clear
dict_remove(ages#, "Bob")
println "After remove: "; dict_count(ages#)   ' 2

dict_clear#(ages#)
println "After clear: "; dict_count(ages#)    ' 0

' Type info
println dict_typename$(ages#)              ' numeric
⚠ Warning: dict_key$() uses 0-based indexing. Iterate from 0 to dict_count(d#) - 1. Key order is not guaranteed.

Error Handling

ErrorDescription
Null dictionary pointerThe dictionary pointer is null
Invalid dictionary objectThe pointer doesn’t point to a valid dictionary
Type mismatchWrong dictionary type for the operation (e.g. using dict_get on a string dict)
Key not foundAttempted to get a non-existent key without using a default variant
Index out of boundsInvalid index in dict_key$
╯ plan9basic
ages# = dict#()

' Safe pattern: always check before get
if dict_exists(ages#, "John") = 1 then
    println dict_get(ages#, "John")
else
    println "Key not found"
endif

' Or use getdef for a default value
println dict_getdef(ages#, "John", 0)  ' 0 (no error)

Complete Examples

Phone Book

╯ phonebook.bas
' Phone book using string dictionary
phonebook# = sdict#()

sdict_set#(phonebook#, "John Smith", "555-1234")
sdict_set#(phonebook#, "Mary Johnson", "555-5678")
sdict_set#(phonebook#, "Bob Wilson", "555-9999")

' Look up a number
name$ = "John Smith"
if dict_exists(phonebook#, name$) = 1 then
    println name$; ": "; sdict_get$(phonebook#, name$)
else
    println name$; " not found"
endif

' List all contacts
println ""
println "All contacts:"
for i = 0 to dict_count(phonebook#) - 1
    name$ = dict_key$(phonebook#, i)
    println name$; " -> "; sdict_get$(phonebook#, name$)
next

Word Counter

╯ wordcount.bas
' Count word occurrences
wordCount# = dict#()

data "apple", "banana", "apple", "cherry", "banana", "apple"

for i = 1 to 6
    read word$
    current = dict_getdef(wordCount#, word$, 0)
    dict_set#(wordCount#, word$, current + 1)
next

println "Word frequencies:"
for i = 0 to dict_count(wordCount#) - 1
    word$ = dict_key$(wordCount#, i)
    println word$; ": "; dict_get(wordCount#, word$)
next

Configuration Manager

╯ config.bas
' App config using string dictionary
config# = sdict#()

sdict_set#(config#, "app.name", "MyApp")
sdict_set#(config#, "app.version", "1.0")
sdict_set#(config#, "db.host", "localhost")
sdict_set#(config#, "db.port", "3306")
sdict_set#(config#, "debug.enabled", "false")

appName$ = sdict_get$(config#, "app.name")
timeout$ = sdict_getdef$(config#, "timeout", "30")

println "Application: "; appName$
println "Timeout: "; timeout$

Object Registry

╯ registry.bas
' Store objects in a pointer dictionary
registry# = pdict#()

users# = sdim#(100)
scores# = dim#(100)
settings# = sdict#()

pdict_set#(registry#, "users", users#)
pdict_set#(registry#, "scores", scores#)
pdict_set#(registry#, "settings", settings#)

' Retrieve an object
if dict_exists(registry#, "scores") = 1 then
    myScores# = pdict_get#(registry#, "scores")
    myScores#[1] = 9999
    println "Top score: "; myScores#[1]
endif

Quick Reference

FunctionSignatureDescription
dict#() / sdict#() / pdict#()*@Create numeric / string / pointer dictionary
dict_set#(d#, k$, v)dict_set#@#$nSet numeric value
dict_get(d#, k$)dict_get@#$Get numeric (error if missing)
dict_getdef(d#, k$, def)dict_getdef@#$nGet numeric or default
sdict_set#(d#, k$, v$)sdict_set#@#$$Set string value
sdict_get$(d#, k$)sdict_get$@#$Get string (error if missing)
sdict_getdef$(d#, k$, def$)sdict_getdef$@#$$Get string or default
pdict_set#(d#, k$, v#)pdict_set#@#$#Set pointer value
pdict_get#(d#, k$)pdict_get#@#$Get pointer (error if missing)
pdict_getdef#(d#, k$, def#)pdict_getdef#@#$#Get pointer or default
dict_exists(d#, k$)dict_exists@#$Key exists? (1/0)
dict_haskey(d#, k$)dict_haskey@#$Alias for dict_exists
dict_count(d#)dict_count@#Number of entries
dict_remove(d#, k$)dict_remove@#$Remove key (1=removed, 0=not found)
dict_clear#(d#)dict_clear#@#Remove all entries
dict_type(d#)dict_type@#Type code: 0/1/2
dict_typename$(d#)dict_typename$@#Type name string
dict_key$(d#, idx)dict_key$@#nKey at 0-based index

20 functions: 3 creation + 9 typed get/set + 8 generic operations.