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:
| Length | Signed | Unsigned |
|---|---|---|
| 8-bit | i8 | u8 |
| 16-bit | i16 | u16 |
| 32-bit | i32 | u32 |
| 64-bit | i64 | u64 |
| arch | isize | usize |
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_000The 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:
| Form | Example |
|---|---|
| Decimal | 98_222 |
| Hex | 0xff |
| Octal | 0o77 |
| Binary | 0b1111_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 // f32Floating-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 = falseBooleans 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.2The 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 boundsThis 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 = trueNow let's look at Functions.