Data Types

In this chapter, we'll explore learn about scalar types, compound types, and type annotations in mana.

Data Types

Every value in Mana is of a certain data type, which tells Mana what kind of data is being specified so it knows how to work with that data. We'll look at two data type subsets: scalar and compound.

Mana is a statically typed language, meaning it must know the types of all variables at compile time. The compiler can usually infer what type we want based on the value and how we use it.

Scalar Types

A scalar type represents a single value. Mana has four primary scalar types: integers, floating-point numbers, booleans, and characters.

Integer Types

An integer is a number without a fractional component. Here are Mana's integer types:

LengthSignedUnsigned
8-biti8u8
16-biti16u16
32-biti32u32
64-biti64u64
archisizeusize

Signed integers can be negative; unsigned integers are always positive.

let age: u8 = 25
let temperature: int = -15
let big_number: u64 = 1_000_000_000

The isize and usize types depend on your computer's architecture (64 bits on a 64-bit architecture).

Integer Literals

You can write integer literals in multiple forms:

FormExample
Decimal98_222
Hex0xff
Octal0o77
Binary0b1111_0000

Floating-Point Types

Mana has two floating-point types: f32 and f64. The default is f64:

let x = 2.0        // f64
let y: f32 = 3.0   // f32

Floating-point numbers are represented according to the IEEE-754 standard.

Numeric Operations

Mana supports the basic mathematical operations:

// Addition
let sum = 5 + 10
 
// Subtraction
let difference = 95.5 - 4.3
 
// Multiplication
let product = 4 * 30
 
// Division
let quotient = 56.7 / 32.2
let truncated = 5 / 3  // Results in 1
 
// Remainder
let remainder = 43 % 5
 
// Exponentiation
let squared = 2 ** 3  // 8 (2 to the power of 3)

The Boolean Type

A boolean type has two values: true and false. Booleans are one byte in size:

let t = true
let f: bool = false

Booleans are used primarily in conditionals, such as if expressions.

The Character Type

The char type is Mana's most primitive alphabetic type:

let c = 'z'
let z: char = 'ℤ'
let heart = '❤'

We specify char literals with single quotes, as opposed to string literals which use double quotes. Mana's char type is four bytes and represents a Unicode Scalar Value.

Compound Types

Compound types group multiple values into one type. Mana has two primitive compound types: tuples and arrays.

The Tuple Type

A tuple groups together values with different types:

let tup: (int, f64, bool) = (500, 6.4, true)

The variable tup binds to the entire tuple. To get individual values, use pattern matching:

let tup = (500, 6.4, true)
let (x, y, z) = tup
println("The value of y is: ", y)

You can also access elements directly using a period and index:

let five_hundred = tup.0
let six_point_four = tup.1
let is_true = tup.2

The tuple without any values, (), is called the unit type. It represents an empty value or empty return type.

The Array Type

Unlike a tuple, every element of an array must have the same type. Arrays in Mana have a fixed length:

let a = [1, 2, 3, 4, 5]

Arrays are useful when you want your data allocated on the stack rather than the heap, or when you need a fixed number of elements:

let months = ["January", "February", "March", "April", "May", "June",
              "July", "August", "September", "October", "November", "December"]

You can annotate an array's type with the length and element type:

let a: [5]int = [1, 2, 3, 4, 5]

Accessing Array Elements

Access elements using indexing:

let a = [1, 2, 3, 4, 5]
 
let first = a[0]
let second = a[1]

If you try to access an element past the end of the array, Mana will panic at runtime:

let a = [1, 2, 3, 4, 5]
let index = 10
 
let element = a[index]  // Runtime panic: index out of bounds

This is an example of Mana's memory safety principles in action. Rather than allowing invalid memory access, Mana catches the error immediately.

Type Inference and Annotations

Mana can often infer types, but you can always be explicit:

// Inferred types
let x = 5          // int
let y = 3.14       // f64
let name = "Alice" // string
 
// Explicit annotations
let x: i64 = 5
let y: f32 = 3.14
let enabled: bool = true

Now let's look at Functions.