Table of Contents

Variables and types

What is a variable?

Imagine a box with a label on it. You can put something inside the box, and later you can look at the label to find what's inside. That's a variable.

A variable has three parts:

Creating variables

In Nyx, there are two ways to create a variable:

let — A value that doesn't change

fn main() {
    let name: String = "Alice"
    let age: int = 25
    let pi: float = 3.14159
    let active: bool = true

    print(name)
    print(age)
}

let creates an immutable variable — once you assign a value, you cannot change it. This is the default and the safest option. Most of your variables should use let.

var — A value that can change

fn main() {
    var score: int = 0
    print(score)    // 0

    score = 10
    print(score)    // 10

    score = score + 5
    print(score)    // 15
}

var creates a mutable variable — you can change its value as many times as you want.

Why have both?

If you use let and accidentally try to change a value, the compiler will tell you. This catches mistakes early. Use var only when you genuinely need the value to change.

fn main() {
    let name: String = "Alice"
    name = "Bob"    // ERROR: cannot assign to immutable variable
}

The four basic types

Nyx has four fundamental types of data:

int — Whole numbers

fn main() {
    let count: int = 42
    let negative: int = -7
    let zero: int = 0
    let big: int = 1000000

    print(count)       // 42
    print(negative)    // -7
}

Integers are whole numbers — no decimal point. They can be positive, negative, or zero. Use them for counting, indexing, and anything that doesn't need fractions.

float — Decimal numbers

fn main() {
    let temperature: float = 36.6
    let price: float = 9.99
    let ratio: float = 0.5

    print(temperature)    // 36.6
}

Floats are numbers with a decimal point. Use them for measurements, prices, percentages, and scientific calculations.

String — Text

fn main() {
    let greeting: String = "Hello"
    let empty: String = ""
    let sentence: String = "Nyx is a compiled language."

    print(greeting)     // Hello
    print(sentence)     // Nyx is a compiled language.
}

Strings are sequences of characters — text. They are always enclosed in double quotes "...". Note that String starts with a capital letter — this is a convention in Nyx for complex types.

bool — True or false

fn main() {
    let is_active: bool = true
    let is_deleted: bool = false

    print(is_active)    // true
    print(is_deleted)   // false
}

Booleans have only two possible values: true or false. They are used for conditions and decisions (you'll learn more about this in Chapter 4).

Type inference

In many cases, Nyx can figure out the type automatically:

fn main() {
    let name = "Alice"     // Nyx knows this is a String
    let age = 25           // Nyx knows this is an int
    let pi = 3.14          // Nyx knows this is a float
    let active = true      // Nyx knows this is a bool

    print(name)
    print(age)
}

When you write let name = "Alice", Nyx sees the double quotes and knows the value is a String. You don't need to write : String explicitly — but you can if you want to be clear about your intentions.

For this book, we will write the types explicitly in most examples so you can see exactly what type each variable is. In practice, experienced programmers often let the compiler infer the types.

Naming rules

Variable names in Nyx must follow these rules:

fn main() {
    let user_name: String = "Alice"        // good
    let age2: int = 25                     // good
    let _temp: int = 100                   // good
    let camelCase: String = "also fine"    // good

    // let 2fast: int = 0       // ERROR: starts with a number
    // let let: int = 0         // ERROR: reserved word
    // let my-name: String = "" // ERROR: hyphens not allowed
}

Convention: Nyx uses snake_case for variables and functions (words separated by underscores, all lowercase). Structs and types use PascalCase (each word capitalized, no separators).

let user_name: String = "Alice"    // snake_case for variables
let max_retries: int = 3           // snake_case for variables

struct UserProfile {                // PascalCase for types
    name: String,
    age: int
}

Converting between types

Sometimes you need to convert a value from one type to another:

fn main() {
    // int to String
    let age: int = 25
    let age_text: String = int_to_string(age)
    print("Age: " + age_text)    // Age: 25

    // String to int
    let input: String = "42"
    let number: int = string_to_int(input)
    print(number + 8)            // 50
}

You cannot mix types directly:

fn main() {
    let age: int = 25
    print("I am " + age)    // ERROR: cannot add String and int
}

Instead, convert the int to a String first:

fn main() {
    let age: int = 25
    print("I am " + int_to_string(age))    // I am 25
}

Exercises

  1. Create variables for your name, age, and favorite number. Print all three.
  1. Create a mutable variable counter starting at 0. Increment it three times (add 1 each time) and print the result after each increment.
  1. Try creating a let variable and changing it. Read the error message the compiler gives you.
  1. What type would you use for each of these?

Summary

Next chapter: Operations and expressions →

← Previous: What is programming? Next: Operations and expressions →