THE NOQERI FIELD GUIDE / BASICS
Find your footing. Learn Noqeri.
Eighteen short lessons to take your first steps: source files, types, control flow, collections and constants. Follow the trail from a single print to programs of your own.
Noqeri v0.1.4 developer preview. These examples teach the checked Stage-0 language surface. Some collection features have narrower qualification.
← THE FULL FIELD GUIDESET UP YOUR FIRST PROGRAM ↗BASICS / 01 OF 18
Hello world
Your first howl
Start with a simple program. Noqeri can print directly from a source file, and functions make calculations reusable.
function add(a: int, b: int): int {
return a + b
}
print("Hello from Noqeri")
print(add(10, 20))TRY THIS: Save this as hello.noqeri. Run `noqeri check hello.noqeri` to type-check it, then `noqeri run hello.noqeri` to see the output.
SEE THE SOURCE ↗BASICS / 02 OF 18
Modules
Keep source in the pack
A module gives related definitions a shared home. You can declare an organizational module name, or keep your source grouped into small .noqeri files.
module graphics.raster
function square(x: int): int {
return x * x
}TRY THIS: A module declaration names a source unit. Import files relative to the file that needs them.
SEE THE SOURCE ↗BASICS / 03 OF 18
Imports
Follow the source trail
Use `import` and a quoted relative filename to bring another Noqeri source file into a project. The compiler resolves and checks the connected declarations as a module graph.
import "math.noqeri"
// The compiler resolves this relative to this file.TRY THIS: Place math.noqeri beside the importing file, or adjust the relative path to match your project.
SEE THE SOURCE ↗BASICS / 04 OF 18
Type checking
Spot errors before they run
Noqeri checks the types of parameters, return values and local bindings. Annotate important boundaries, and rely on inference when an initializer already makes the type clear.
function double(x: int): int {
return x * 2
}
let value: int = double(21)
print(value)
// let broken: int = "not a number"TRY THIS: Uncomment the intentionally incorrect assignment and run `noqeri check` to inspect the diagnostic.
SEE THE SOURCE ↗BASICS / 05 OF 18
Ints
Whole-number building blocks
Use `int` for ordinary signed whole numbers. Noqeri also provides signed and unsigned fixed-width integers when binary formats or hardware layouts require them.
let a: int = 8
let b: int = 3
print(a + b)
print(a * b)
print(a > b)TRY THIS: Choose a fixed-width type for a real storage or ABI reason; normal application arithmetic generally begins with `int`.
SEE THE SOURCE ↗BASICS / 06 OF 18
Floats
Numbers with a decimal
Use `float` for fractional numeric values. Write arithmetic with familiar `+`, `-`, `*` and `/` operators, and keep calculations in compatible numeric types.
let price: float = 7.5
let count: float = 2.0
let total: float = price * count
print(total)TRY THIS: Floating-point representation and supported operations can vary by compilation target; verify your deployment target when accuracy matters.
SEE THE SOURCE ↗BASICS / 07 OF 18
Number formats
Numbers you can read
Noqeri supports ordinary numeric literals and explicit casts when you need a specific width. Hexadecimal constants are also useful for low-level addresses and bit patterns.
let decimal: int = 1000
let address: usize = 0x1000
let weight: float = 0.25
print(decimal)TRY THIS: Keep width-sensitive casts explicit, and use `noqeri check` to verify numeric literal forms for your installed compiler.
SEE THE SOURCE ↗BASICS / 08 OF 18
Equality
Check what's equal
Use `==` and `!=` to compare supported values. Ordered comparisons such as `<`, `>` and `>=` work where the operand types support ordering.
let x: int = 10
print(x == 10)
print(x != 3)
print(x >= 5)TRY THIS: Equality and ordering are statically checked; make sure both sides have compatible types.
SEE THE SOURCE ↗BASICS / 09 OF 18
Strings
Give your code a voice
Write ordinary text inside double quotes and print it when your program needs to communicate with a user or terminal. String values use the `string` type.
const language = "Noqeri"
print("Hello from Noqeri")
print(language)TRY THIS: String interpolation with typed placeholders is still being developed. Use supported library functions for any additional formatting needs.
SEE THE SOURCE ↗BASICS / 10 OF 18
Bools
Two clear answers
A `bool` stores `true` or `false`. Combine boolean conditions with `&&`, `||` and `!` to make readable decisions.
let ready: bool = true
let tired: bool = false
if ready && !tired {
print("Ready to build")
}TRY THIS: An `if` condition can omit surrounding parentheses: `if ready { ... }` is valid.
SEE THE SOURCE ↗BASICS / 11 OF 18
Assignments
Give it a name
Use `let` for a local binding and `=` to update a mutable value. Use `const` when the binding must stay unchanged.
let score = 3
score = score + 2
const project = "Noqeri"
print(score)TRY THIS: Try changing the score with `score = score + 2` and printing the result.
SEE THE SOURCE ↗BASICS / 12 OF 18
Unused values
Keep the trail tidy
Choose clear names for values your code uses. When a computation exists only for its effect, keeping the expression simple makes intent easier to follow.
let total = 4
print(total)
// Use meaningful names for values you keep.TRY THIS: Unused-binding diagnostics depend on the compilation context. This lesson focuses on clear naming and explicit control flow.
SEE THE SOURCE ↗BASICS / 13 OF 18
Type annotations
Tell the compiler your intent
Write `: int`, `: bool` or another type after a binding name when you want an explicit contract. Noqeri can infer many local types from their initializers.
let count: int = 4
let active: bool = true
let name = "Noqeri"
print(name)TRY THIS: Function signatures are an especially useful place for explicit types and clear return values.
SEE THE SOURCE ↗BASICS / 14 OF 18
Types across files
Share shapes between modules
Name a data shape with a `record`, then place its declaration in a source file that other parts of your project import.
import "models.noqeri"
// models.noqeri can declare:
// record User {
// id: u64
// active: bool
// }TRY THIS: A relative import includes the source declarations in the checked graph. Keep record names consistent across your project.
SEE THE SOURCE ↗BASICS / 15 OF 18
Named records
Shape your own data
Records give a collection of fields a meaningful name. Define a record for the data your program passes between functions instead of relying on unrelated scalar arguments.
record User {
id: u64
active: bool
}TRY THIS: Generic records use `record Box<T> { ... }` when you want the same shape with different field types.
SEE THE SOURCE ↗BASICS / 16 OF 18
Blocks
Small scopes, clear paths
Curly braces group the body of functions, conditions, loops and other statements. Each block keeps the statements inside it together.
function check(value: int): int {
if value > 0 {
return value
}
return 0
}
print(check(3))TRY THIS: Use explicit `return` for a value you want a function to produce.
SEE THE SOURCE ↗BASICS / 17 OF 18
Lists
Keep the pack together
Fixed arrays and slices handle collections with predictable storage. Noqeri also has qualified growable lists for selected scalar types, with append, indexing and basic lifecycle operations.
let numbers = [5, 10]
numbers.append(15)
print(numbers.length())
for number in numbers {
print(number)
}TRY THIS: The growable list implementation is currently qualified for scalar `int`, `float` and `bool` cases. General element ownership is still being completed.
SEE THE SOURCE ↗BASICS / 18 OF 18
Constants
Names that stay put
`const` creates a binding you cannot reassign. It is useful for limits, application settings and names that should remain stable.
const max_attempts = 3
let attempt = 1
if attempt <= max_attempts {
print("Try again")
}TRY THIS: Use `const` for stable bindings and `let` when the value needs to change during execution.
SEE THE SOURCE ↗Ready to run with the pack?
You've learned the foundations. Next, give your ideas structure with reusable functions, typed parameters and meaningful return values.
CONTINUE TO FUNCTIONS ↗BUILD YOUR FIRST PROJECT ↗