Types
Every value in Tessel has a type, and the type of every variable is known
before the program runs. tessel check uses this to catch mistakes, like
adding a number to a piece of text, before you ever run your code.
You rarely have to write types yourself: Tessel infers them from the values you use. You do write them for function parameters, return values, struct fields, and empty lists or dictionaries.
Overview
Section titled “Overview”| Type | Example values | What it holds |
|---|---|---|
Int | 0, 42, -7, 1_000 | A whole number (64-bit) |
Float | 0.5, 3.14, 2.0 | A decimal number (64-bit) |
Bool | true, false | A truth value |
String | "hi", "Hello, {name}" | Text |
Range | 0..3, 1..n | A range of whole numbers |
Data | Data(text: "hi") | Raw bytes, such as a file’s contents |
[T] | [1, 2, 3] | A list of values of type T |
[K: V] | ["ada": 36] | A dictionary from keys K to values V |
Set<T> | [1, 2] (where a set is expected) | A set of values, each once |
(A, B) | (1, "one") | A tuple: a few values grouped together |
T? | nil, 5 | An optional: a T, or nil |
fn(A, B) -> R | { a, b in a + b } | A function |
| structs and enums | Point(x: 1, y: 2), .red | Types you declare yourself |
For building user interfaces there are also View and a few built-in enums
such as Color, Weight, Alignment and IconName. Those are covered in
Building apps.
An Int is a whole number from −9,223,372,036,854,775,808 to
9,223,372,036,854,775,807 (a 64-bit signed integer).
let year = 2026let big = 1_000_000let negative = -40Int arithmetic never silently wraps around. If a result is too large or too
small to fit, the program stops with an integer overflow error. Dividing by
zero (with / or %) also stops the program. See
Runtime errors.
Dividing two Ints gives an Int and drops the fraction: 7 / 2 is 3.
A Float is a 64-bit floating-point number (a “double” in many languages).
A number literal with a decimal point is a Float.
let price = 9.99let half = 0.5print(10.0 / 4.0) // 2.5print(2.0 * 3.0) // 6.0When a Float is printed or put into a string, a whole value keeps its
.0 (so 6.0, not 6), which makes it easy to tell from an Int. To show
a fixed number of decimals, use formatted:
let third = 1.0 / 3.0print(third) // 0.3333333333333333print(third.formatted(decimals: 2)) // 0.33Math functions like sqrt, pow, sin and round, and the constant pi,
are built in:
let radius = 2.0let area = pi * pow(radius, 2.0)print(area.formatted(decimals: 1)) // 12.6print(sqrt(2.0)) // 1.4142135623730951See Math for the full list.
Float arithmetic follows the usual floating-point rules: it never stops the
program. Dividing by zero gives infinity, which prints as inf. And, as in
most languages, some decimal fractions can’t be stored exactly:
0.1 + 0.2 prints 0.30000000000000004.
A Bool is true or false. Comparisons produce Bools, and if
conditions need one.
let score = 72let passed = score >= 50if passed && score < 80 { print("Passed")}String
Section titled “String”A String is a piece of Unicode text. Strings support interpolation with
{…} and escapes such as \n; see Basics.
let name = "Ada"let greeting = "Hello, {name}!"print(greeting.count) // 11print(greeting.uppercase()) // HELLO, ADA!count counts characters, not bytes, so "héllo".count is 5. The full
list of string properties and methods is on the
Collections page.
Strings can’t be indexed with […]. Use character(at:) for one
character, characters for all of them as a list, or methods like
substring, split, contains or hasPrefix.
a..b is a Range: the whole numbers from a up to, but not including, b.
You can loop over a range, store it, pass it around, compare two ranges with
==, and print one:
struct Chapter { title: String pages: Range}
let intro = Chapter(title: "Intro", pages: 1..4)for page in intro.pages { print("page {page}") // page 1, page 2, page 3}print(intro.pages) // 1..4Data is a sequence of bytes: the contents of a file that isn’t text, or
values encoded with toBinary. Make one with Data(),
Data(bytes: [72, 105]) or Data(text: "Hi"); data.count is its size and
data[i] a byte, as an Int from 0 to 255.
let greeting = Data(text: "Hi")print(greeting.count) // 2print(greeting[0]) // 72See Data in the standard library reference.
[T] is an ordered list whose items all have type T:
let primes = [2, 3, 5, 7] // [Int]var names: [String] = [] // an empty [String]names.append("Grace")print(primes[0]) // 2Dictionaries
Section titled “Dictionaries”[K: V] maps keys of type K to values of type V:
var ages = ["ada": 36, "alan": 41] // [String: Int]ages["grace"] = 85print(ages["ada"] ?? 0) // 36Keys can be Int, String, Bool, an enum whose cases carry no values,
or a tuple or struct made of those. Looking up a key gives an optional,
because the key might be missing.
Sets and tuples
Section titled “Sets and tuples”Set<T> holds values without order and without repeats, and (A, B) is a
tuple, a few values of any types grouped together:
var seen: Set<Int> = [1, 2, 2] // 2 valuesseen.insert(3)let pair = (1, "one") // (Int, String)print(pair.1) // oneLists, dictionaries and sets have many methods, and tuples can be taken
apart with let (a, b) = pair; see Collections.
Optionals
Section titled “Optionals”T? is “a T, or nothing”. The nothing value is written nil:
var nickname: String? = nilnickname = "Countess"print(nickname ?? "no nickname")You can’t use an optional as if it were a plain value. You unwrap it first
with if let, ?? or ?.. See Optionals and Errors.
Function types
Section titled “Function types”Functions are values too. Their type is written with fn:
| Type | A function that… |
|---|---|
fn() | takes nothing and returns nothing |
fn(Int) -> Bool | takes an Int and returns a Bool |
fn(String, Int) -> String | takes a String and an Int, returns a String |
fn() -> Int | takes nothing and returns an Int |
let isEven: fn(Int) -> Bool = { n in n % 2 == 0 }print(isEven(4)) // trueTo make a function type optional, the ? goes at the end: fn()? is an
optional function. See Closures.
Structs and enums
Section titled “Structs and enums”You can declare your own types:
struct Point { x: Float y: Float}
enum Suit { hearts, diamonds, clubs, spades }See Structs and enums.
Type inference
Section titled “Type inference”Tessel works out a variable’s type from its starting value:
let count = 3 // Intlet price = 9.99 // Floatlet names = ["a", "b"] // [String]let lookup = ["a": 1] // [String: Int]let isOn = count > 2 // BoolWrite the type after a colon when you want a different one, or when Tessel can’t tell:
let ratio: Float = 1 // a Float, not an Intvar items: [String] = [] // an empty list has no items to look atvar cache: [String: Int] = [:]var selected: Int? = nil // nil alone doesn't say what's missingWithout the type, an empty list is an error:
var items = []error: can't tell what type this empty list is = help: give it a type, like `var names: [String] = []`Function parameters and return types are always written out. See Functions.
Converting between types
Section titled “Converting between types”Tessel never converts between types on its own. A variable of type Int is
never used as a Float, or turned into text, unless you ask for it. You
convert with Int(…), Float(…) and String(…):
| Conversion | From | Result | Notes |
|---|---|---|---|
Float(x) | Int or Float | Float | Float(7) is 7.0 |
Int(x) | Int or Float | Int | Drops the fraction: Int(3.99) is 3, Int(-2.99) is -2 |
Int(text) | String | Int? | nil if the text isn’t a whole number |
Float(text) | String | Float? | nil if the text isn’t a number |
String(x) | Int, Float, Bool, String or an enum | String | Same text as "{x}" |
let count = 7print(Float(count) / 2) // 3.5print(Int(3.99)) // 3print(Int("42") ?? 0) // 42print(Int("forty-two") ?? 0) // 0print(Float("2.5") ?? 0) // 2.5print(String(12) + " items") // 12 itemsParsing text can fail, so Int("…") and Float("…") return optionals.
Spaces around the number are ignored, so Int(" 12 ") is 12. Int("12.5")
is nil, because 12.5 is not a whole number.
Int(x) on a Float that is too large for an Int gives the largest (or
smallest) Int instead of stopping the program.
Mixing types by mistake gives an error that suggests the conversion:
let count = 7let half = count / 2.0error: can't use `/` on `Int` and `Float` = help: convert one side with `Float(…)` or `Int(…)`