Chapters

Values, Variables, and Basic Types

This chapter covers numbers, strings, and mutable state. Each example runs as a single file: save it and execute tauto run filename.

3.1 Give values names

let names a value. var creates a cell whose contents can be changed. Assignment uses :=; new bindings also use let x := value and var x := value.

ch03-let.taut
let a := 10
let b: i64 := 32
perform show("sum", a + b)

var count: i64 := 0
count := count + 1
perform show("count", count)

// A mutable binding can change, while a let binding cannot be reassigned.
Execution result
sum = 42
count = 1
sum = 42
count = 1

A let binding cannot be reassigned; a var binding can. Ownership rules apply to both (Chapter 7).

3.2 Types determine what numbers mean

Numeric types have explicit meanings.

TypeMeaningKey point
i32, i64Fixed-width signed integersArithmetic overflow is a runtime error
u8, u32, u64Fixed-width unsigned integersArithmetic does not implicitly convert widths
DecimalExact decimal numbersUseful for decimal calculations such as money
FloatFloating-point numbersAccount for approximation error
Booltrue / falseUsed in conditions
TextStringsShared data that can be duplicated
()The unit typeComputations with no meaningful result
NeverA type with no valuesUsed for computations that do not return

Tauto does not automatically mix i64 and i32 in addition. Trying it produces a type error.

ch03-mix-error.taut
let a: i32 := 1
let b: i64 := 2
perform show("x", a + b)

// This deliberately mixes integer widths and must be rejected.
✗ Error
✗ program

error 3:19: `+` of i32 and i64: the operands differ
ch03-mix-error.taut:3:19: type error: `+` of i32 and i64: the operands differ

To change widths, use explicit conversions such as I64::of_i32 or I32::of_i64. A value outside the destination's range is not silently rounded; it causes a runtime error (the number is too large).

ch03-convert.taut
let a: i32 := 1
let b: i64 := 2
perform show("sum", I64::of_i32(a) + b)
perform show("back", I32::of_i64(b))

// Convert the integer width explicitly before adding.
Execution result
sum = 3
back = 2
sum = 3
back = 2

3.3 Arithmetic and comparisons

Integer division does not use /. Use the dedicated functions div(a, b) and mod(a, b).

ch03-arith.taut
let a := 7
let b := 3
let product := a * b
let quotient := div(a, b)
let remainder := mod(a, b)
let same := a == b
perform show("p", product)
perform show("q", quotient)
perform show("r", remainder)
perform show("same", same)

// Observe multiplication, division, remainder, and comparison separately.
Execution result
p = 21
q = 2
r = 1
same = false
p = 21
q = 2
r = 1
same = false

Writing 7 / 2 produces an error explaining the available forms:

type error: integer `/` is a type error: write div(a, b), mod(a, b), or decimal(a) / decimal(b)

Division by zero is a runtime error. It is not necessarily ruled out before execution.

3.4 Strings

Strings have type Text. Double-quoted literals ("...") process escapes, while single-quoted literals ('...') do not.

ch03-text.taut
import std::prelude::Shared

let greeting := "Hello, Tauto!"
let path := 'C:\Users\example\Documents'
let joined := concat(greeting, " Good day")
perform show("text", joined)
perform show("path", path)

// Concatenate text explicitly and preserve backslashes in the raw path.
Execution result
text = "Hello, Tauto! Good day"
path = "C:\\Users\\example\\Documents"
text = "Hello, Tauto! Good day"
path = "C:\\Users\\example\\Documents"

show formats values for display, so the path's backslashes appear doubled in the output. The value itself is C:\Users\example\Documents.

To concatenate Text, use concat, not +. The expression "x" + "y" is a type error: +` of Text: not a number. Numeric and string operations are designed to have an unambiguous meaning.

Exercise 3.1: Bind two integers with let and observe their sum, difference, and product with show.