Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lists, text and namespaces

Lists

A list is an ordered sequence of values, written in square brackets.

nums = [10, 20, 30]
nums                 # => [10, 20, 30]
[]                   # => []

The brackets enclose an expression, usually a tuple, and the list contains its items. Since tuples are flat, a tuple inside the brackets adds its items directly, and Nothing adds nothing. A list inside a list stays a single item:

[1, (2, 3)]          # => [1, 2, 3]
[1, (), 2]           # => [1, 2]
[[1, 2], [3]]        # => [[1, 2], [3]]

Getting items

Apply a list to a number to get the item at that position. Positions start at 0. A position that is negative, fractional or past the end gives Nothing.

nums = [10, 20, 30]
nums 0               # => 10
nums 2               # => 30
nums 10              # => ()
nums (0, 2)          # => (10, 30)

Combining and transforming

+ concatenates lists. The list namespace has functions to measure, search and slice them.

nums = [10, 20, 30]
nums + [40]          # => [10, 20, 30, 40]
list.size nums       # => 3
list.find 20 nums    # => 1
list.head 2 nums     # => [10, 20]
list.reverse nums    # => [30, 20, 10]

Lists are values: no operation changes a list. To process each item, turn the list into a tuple with list.enum, map a function over it, and put the result back in brackets:

prices = [5, 12, 20]
[list.enum prices => (p -> p * 2)]   # => [10, 24, 40]

Text

Text values support + (concatenation) and comparison. Applying a text to a number gives the character at that position, starting at 0. Positions count Unicode characters, not bytes.

word = "swan"
word 0               # => "s"
word (1, 2)          # => ("w", "a")
word 10              # => ()
"sw" + "an" == word  # => TRUE

The text namespace has functions to measure, search, slice, split and join text.

text.size "héllo"    # => 5
text.upper "texl"    # => "TEXL"
text.split "," "a,b,c"         # => ("a", "b", "c")

Namespaces

A namespace is a set of named values, written in curly braces.

point = {x: 3, y: 4}
point                # => {x: 3, y: 4}

The braces enclose an expression, which Swan evaluates in a new scope. Every name bound during that evaluation becomes a member of the namespace. The members can use the members defined before them, and the names around the namespace:

scale = 10
box = {width: 2, height: width * 3, area: width * height * scale}
box.area             # => 120

You can bind members with : or =. Inside the braces, the separators are just the comma operator, so any expression works, including definitions of functions:

counter = {start = 1, next = n -> n + 1}
counter.next counter.start     # => 2

Reading members

There are two ways to read a member:

  • ns.name evaluates name inside the namespace. The right side can be any expression, and it can use all the members.
  • ns "name" looks up the member called "name". The key is a text value, so it can be computed.
point = {x: 3, y: 4}
point.x              # => 3
point.(x * y)        # => 12
point "y"            # => 4
key = "x"
point key            # => 3
point "z"            # => ()

The two differ for names that are not members. ns "name" only sees the members of the namespace, while ns.name also sees the names around the place where the namespace was created, like any expression evaluated inside it:

point = {x: 3, y: 4}
point "math"         # => ()
type point.math      # => "Namespace"

Reading a member of Nothing gives Nothing, so a chain of . stops safely at the first missing link:

config = {}
config.server.port   # => ()

Adding members

A namespace can gain members after it is created. Bind them inside the namespace with .:

point = {x: 3}
point.(y = 4)
point                # => {x: 3, y: 4}

Inspecting namespaces

The nspace namespace lists and counts the members:

point = {x: 3, y: 4}
nspace.enum point    # => ("x", "y")
nspace.size point    # => 2

Namespaces as modules

Namespaces group related functions, like the built-in math and text namespaces:

geometry = {
    square = side -> side * side,
    circle = radius -> math.PI * radius ^ 2
}
geometry.square 3    # => 9