Types & Variables

Quartz is a dynamically-typed language, meaning you don't need to declare types explicitly. However, understanding the type system helps you write better code.

Primitive Types

Integers

Whole numbers, positive or negative:

let count = 42
let negative = -17
let zero = 0
let big = 1000000

Floating-Point Numbers (Doubles)

Numbers with decimal points:

let pi = 3.14159
let temperature = -40.5
let tiny = 0.0001
let scientific = 1.5e10  // 1.5 × 10^10

Booleans

True or false values:

let isActive = true
let isEmpty = false

// Boolean expressions
let isAdult = age >= 18
let canDrive = hasLicense && isAdult

Strings

Text enclosed in double quotes:

let name = "Quartz"
let message = "Hello, World!"
let empty = ""

// String concatenation
let greeting = "Hello, " + name + "!"

// Escape sequences
let newline = "Line 1\nLine 2"
let tab = "Column1\tColumn2"
let quote = "She said \"Hello\""

Null

Represents absence of a value:

let nothing = null

// Check for null
if (value == null) {
io.println("No value")
}

Composite Types

Arrays

Ordered collections of values:

// Create arrays
let numbers = [1, 2, 3, 4, 5]
let names = ["Alice", "Bob", "Charlie"]
let mixed = [1, "two", 3.0, true]
let empty = []

// Access by index (0-based)
let first = numbers[0]    // 1
let second = numbers[1]   // 2

// Modify elements
numbers[0] = 10

// Array length
let size = len(numbers)   // 5

// Nested arrays
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
let center = matrix[1][1] // 5

Dictionaries

Key-value collections:

// Create dictionaries
let person = {
"name": "Alice",
"age": 30,
"city": "Boston"
}

// Access by key
let name = person["name"]

// Modify values
person["age"] = 31

// Add new keys
person["email"] = "alice@example.com"

// Nested dictionaries
let company = {
"name": "TechCorp",
"employees": {
"ceo": "John",
"cto": "Jane"
}
}
let ceo = company["employees"]["ceo"]

Variable Declaration

The let Keyword

Declare variables with let:

let name = "Quartz"
let count = 0
let items = []

Assignment

Assign new values with =:

let x = 10
x = 20        // Reassignment
x = x + 1     // Increment

Compound Assignment

Shorthand operators for modification:

let x = 10
x += 5    // x = x + 5  → 15
x -= 3    // x = x - 3  → 12
x *= 2    // x = x * 2  → 24
x /= 4    // x = x / 4  → 6
x %= 4    // x = x % 4  → 2

Multiple Variables

let a = 1
let b = 2
let c = 3

// Or on separate lines with context
let name = "Alice"
let age = 30
let email = "alice@example.com"

Type Conversion

Built-in Conversion Functions

// String to integer
let numStr = "42"
let num = int(numStr)     // 42

// String to float
let piStr = "3.14"
let pi = double(piStr)    // 3.14

// Number to string
let n = 42
let s = str(n)            // "42"

// Boolean conversion
let b = bool(1)           // true
let b2 = bool(0)          // false
let b3 = bool("")         // false
let b4 = bool("hello")    // true

Type Checking

import system.runtime as rt

let value = 42

// Check type
if (rt.typeOf(value) == "int") {
io.println("It's an integer!")
}

// Type name
io.println(rt.typeOf("hello"))   // "string"
io.println(rt.typeOf([1, 2, 3])) // "array"
io.println(rt.typeOf({"a": 1}))  // "dict"

Operators

Arithmetic Operators

Operator Description Example Result
`+`Addition`5 + 3``8`
`-`Subtraction`5 - 3``2`
`*`Multiplication`5 * 3``15`
`/`Division`7 / 2``3.5`
`%`Modulo`7 % 3``1`

Comparison Operators

Operator Description Example Result
`==`Equal`5 == 5``true`
`!=`Not equal`5 != 3``true`
`<`Less than`3 < 5``true`
`>`Greater than`5 > 3``true`
`<=`Less or equal`5 <= 5``true`
`>=`Greater or equal`5 >= 3``true`

Logical Operators

Operator Description Example Result
`&&`Logical AND`true && false``false`
`||`Logical OR`true || false``true`
`!`Logical NOT`!true``false`

String Operator

// String concatenation with +
let full = "Hello" + " " + "World"  // "Hello World"

// Concatenate with other types (auto-converts to string)
let msg = "Count: " + 42            // "Count: 42"

Variable Scope

Variables are scoped to their enclosing block:

let global = "I'm global"

fn example() {
let local = "I'm local"

if (true) {
let blockScoped = "I'm in a block"
io.println(global)      // Works
io.println(local)       // Works
io.println(blockScoped) // Works
}

// io.println(blockScoped) // Error: not in scope
}

// io.println(local) // Error: not in scope

Shadowing

Inner scope can shadow outer variables:

let x = 10

fn example() {
let x = 20     // Shadows outer x
io.println(x)  // 20
}

example()
io.println(x)      // 10 (unchanged)

Constants by Convention

Quartz doesn't have a const keyword. Use SCREAMING_CASE by convention:

let MAX_SIZE = 100
let PI = 3.14159
let APP_NAME = "MyApp"

// These are still technically mutable, but by convention
// SCREAMING_CASE signals "don't modify this"

Next: Control Flow →