🪄 V Philosophy & Introduction

🎯 What is V?

V (Vlang) is a statically typed, compiled programming language created by Alexander Medvednikov. V aims for simplicity, performance, and safety. It compiles to native code via C, producing fast executables with zero dependencies. V features a clean syntax similar to Go, but with memory safety (no null, no global variables), fast compilation (100k lines/sec), and built-in GUI library.

🔬 Core Principles

  • No null: All values are initialized, optional types for nullable values.
  • No globals: Encourages functional purity and testability.
  • No undefined behavior: Array bounds checking, no pointer arithmetic.
  • Fast compilation: Compiles millions of lines per second.
  • Autofree: Automatic memory management without GC overhead.
  • Built-in GUI: Native UI framework (UI, graphics, web).
// V: Simplicity meets performance module main fn main() { println("Hello, Vlang!") // No null, no globals name := "V" println("Language: $name") // Fast compilation and clean syntax numbers := [1, 2, 3, 4, 5] for n in numbers { println(n) } }

📦 Variables & Type System

🎯 Immutability by Default

Variables are immutable by default (:=). Use mut for mutable variables. Strong static typing with type inference. Primitive types: int, i8-u64, f32, f64, byte, bool, string.

module main fn main() { // Immutable by default name := "Vlang" // name = "Other" // Error: cannot assign to immutable // Mutable variables mut count := 0 count++ // Explicit typing age: int = 25 pi: f64 = 3.14159 is_active: bool = true // Constants const version = "0.4.0" const max_size = 1000 // Type aliases type UserId = int uid := UserId(12345) // Option type (nullable) mut maybe_name: ?string = none maybe_name = "Alice" if name := maybe_name { println(name) } // String interpolation println("$name is $age years old") }

⚙️ Functions & Methods

🎯 First-Class Functions

Functions are first-class citizens. Support for multiple returns, named returns, variadic parameters, and closures.

module main // Basic function fn add(x int, y int) int { return x + y } // Multiple returns fn divide(a, b int) (int, string) { if b == 0 { return 0, "division by zero" } return a / b, "" } // Named returns fn multiply(x, y int) (result int) { result = x * y return } // Variadic function fn sum(numbers ...int) int { mut total := 0 for n in numbers { total += n } return total } // Closure fn make_adder(x int) fn(int) int { return fn (y int) int { return x + y } } // Method on struct struct Counter { mut: value int } fn (mut c Counter) inc() { c.value++ } fn (c Counter) get() int { return c.value } fn main() { println(add(5, 3)) q, err := divide(10, 2) println("$q, $err") adder := make_adder(10) println(adder(5)) // 15 mut c := Counter{} c.inc() c.inc() println(c.get()) // 2 }

🔀 Control Flow Mastery

🎯 Conditionals & Pattern Matching

if/else with conditions, match for pattern matching (like switch on steroids), and or for option handling.

module main fn main() { score := 85 // If-else if score >= 90 { println("A+") } else if score >= 80 { println("B") } else { println("C") } // If as expression status := if score >= 60 { "pass" } else { "fail" } println(status) // Match (pattern matching) day := "Monday" match day { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" { println("Weekday") } "Saturday", "Sunday" { println("Weekend") } else { println("Invalid") } } // Match with ranges number := 42 match true { number < 0 { println("negative") } number >= 0 && number <= 100 { println("between 0-100") } else { println("large") } } // Option handling with or mut maybe_val: ?int = none val := maybe_val or { 0 } // Default if none println(val) }

🔄 Loops & Iteration

🎯 For Loop Versatility

V has a single for loop that can be used as range loop, while loop, and infinite loop.

module main fn main() { // Range loop for i in 0..5 { println(i) // 0,1,2,3,4 } // Range with step for i in 0..10 step 2 { println(i) // 0,2,4,6,8 } // While-style mut i := 0 for i < 5 { println(i) i++ } // Infinite loop with break mut count := 0 for { count++ if count > 3 { break } println(count) } // Iterate over array names := ["Alice", "Bob", "Charlie"] for name in names { println(name) } // With index for index, name in names { println("$index: $name") } // Continue and labels outer: for i in 0..3 { for j in 0..3 { if i == j { continue outer } println("$i, $j") } } }

📊 Arrays & Maps

🎯 Dynamic Collections

Arrays are dynamic, bounds-checked, and support slicing. Maps are hash tables with any key type.

module main fn main() { // Arrays mut numbers := [1, 2, 3, 4, 5] numbers << 6 // Append numbers << [7, 8, 9] // Append multiple println(numbers) // [1,2,3,4,5,6,7,8,9] println(numbers.len) // Fixed-size array fixed: [5]int = [1,2,3,4,5] // Multi-dimensional matrix := [[1,2,3], [4,5,6], [7,8,9]] // Array methods println(numbers[1..4]) // Slice numbers.delete(2) // Remove at index numbers.reverse() numbers.sort() // Array initialization zeros := [0].repeat(10) // [0,0,0,0,0,0,0,0,0,0] // Maps mut ages := map[string]int{ "Alice": 30 "Bob": 25 } ages["Charlie"] = 35 ages.delete("Bob") for name, age in ages { println("$name: $age") } // Check existence if val := ages["Alice"] { println("Alice is $val") } else { println("Not found") } }

🏗️ Structs & Interfaces

🎯 Object-Oriented without Inheritance

Structs with methods, embedding (composition over inheritance), and interfaces for polymorphism.

module main // Struct definition struct Person { name string age int mut: email string // Mutable field } // Methods fn (p Person) greet() string { return "Hello, I'm ${p.name}" } fn (mut p Person) set_email(email string) { p.email = email } // Struct embedding (composition) struct Employee { Person // Embedding position string } // Interface interface Speaker { speak() string } struct Dog { name string } fn (d Dog) speak() string { return "Woof!" } struct Cat { name string } fn (c Cat) speak() string { return "Meow!" } fn make_sound(s Speaker) { println(s.speak()) } fn main() { mut p := Person{ name: "Alice" age: 30 email: "alice@example.com" } println(p.greet()) p.set_email("new@example.com") // Embedded struct e := Employee{ Person: Person{ name: "Bob" age: 25 email: "bob@work.com" } position: "Developer" } println(e.greet()) // Interface dog := Dog{"Rex"} cat := Cat{"Whiskers"} make_sound(dog) make_sound(cat) }

🛡️ Error Handling (Option/Result)

🎯 No Exceptions, Just Values

V uses Option (nullable) and Result types for error handling. No try/catch, just values.

module main import os // Function returning Result fn safe_divide(a int, b int) ?int { if b == 0 { return none // Option: none } return a / b } // Function with custom error fn read_file(path string) !string { content := os.read_file(path) or { return error("Failed to read: $path") } return content } // Custom error type struct MyError { code int msg string } fn risky_operation(x int) !int { if x < 0 { return MyError{code: 400, msg: "negative not allowed"} } return x * 2 } fn main() { // Option handling result := safe_divide(10, 2) if val := result { println("Result: $val") } else { println("Division by zero") } // Using or with default val := safe_divide(10, 0) or { 0 } println(val) // 0 // Result propagation content := read_file("test.txt") or { println("Error: $err") return } println(content) // Match on result match risky_operation(5) { .ok(value) { println("Success: $value") } .err(err) { println("Error: $err") } } }

⚡ Concurrency (Spawning)

🎯 Lightweight Threads

V uses spawn for concurrent execution. Channels for communication between threads.

module main import sync fn worker(id int, ch chan int) { println("Worker $id started") result := id * id ch <- result // Send result } fn main() { // Channels ch := chan int{cap: 10} // Spawn concurrent tasks for i in 1..5 { spawn worker(i, ch) } // Receive results for _ in 1..5 { result := <-ch println("Got: $result") } ch.close() // Wait groups mut wg := sync.new_waitgroup() for i in 1..3 { wg.add(1) spawn fn (id int, wg &sync.WaitGroup) { defer { wg.done() } println("Task $id complete") }(i, &wg) } wg.wait() println("All done!") // Shared memory with mutex mut m := sync.new_mutex() mut counter := 0 for _ in 0..100 { spawn fn (mut m sync.Mutex, mut counter int) { m.lock() counter++ m.unlock() }(mut m, mut counter) } }

💾 Memory Management (Autofree)

🎯 Automatic without GC

V uses autofree - automatic memory management at compile time. Optional GC for complex cases.

module main import strings // Struct with manual cleanup struct FileHandle { fd int } fn (f &FileHandle) close() { // Manual cleanup if needed println("Closing file descriptor ${f.fd}") } fn main() { // Automatic memory management mut builder := strings.new_builder(100) builder.write_string("Hello") builder.write_string(" ") builder.write_string("V!") result := builder.str() println(result) // Defer for cleanup { f := &FileHandle{fd: 42} defer { f.close() } println("Using file") } // defer runs here // Reference counting with shared shared := &strings.Builder{} shared.write_string("Shared data") // No manual free needed - autofree handles it // For performance-critical code, use -autofree flag }

📦 Modules & Imports

🎯 Simple Module System

Modules organize code. VPM (V Package Manager) for dependencies.

// File: mymodule.v module mymodule pub fn greet(name string) string { return "Hello, $name!" } pub struct User { pub name string age int // private by default } // File: main.v module main import mymodule // Import custom module import os // Standard library import net.http // HTTP client fn main() { // Using imported module msg := mymodule.greet("Vlang") println(msg) user := mymodule.User{ name: "Alice" } println(user.name) // Standard library println(os.getwd()) // HTTP request resp := http.get("https://example.com") or { println("Error: $err") return } println(resp.status_code) // Import with alias import time as t println(t.now()) }

🔧 Generics & Sum Types

🎯 Type-Parametric Programming

Generics for type-safe containers. Sum types for algebraic data types.

module main // Generic struct struct Stack { mut: items []T } fn (mut s Stack) push(item T) { s.items << item } fn (mut s Stack) pop() ?T { if s.items.len == 0 { return none } return s.items.pop() } // Generic function fn max(a T, b T) T { return if a > b { a } else { b } } // Sum type (algebraic data type) type Expr = IntExpr | AddExpr | SubExpr struct IntExpr { value int } struct AddExpr { left Expr right Expr } struct SubExpr { left Expr right Expr } fn evaluate(expr Expr) int { return match expr { IntExpr { expr.value } AddExpr { evaluate(expr.left) + evaluate(expr.right) } SubExpr { evaluate(expr.left) - evaluate(expr.right) } } } fn main() { // Generic stack mut int_stack := Stack{} int_stack.push(10) int_stack.push(20) println(int_stack.pop()) mut str_stack := Stack{} str_stack.push("Hello") str_stack.push("V") // Generic function println(max(10, 20)) println(max(3.14, 2.71)) // Sum type expr := AddExpr{ left: IntExpr{5} right: SubExpr{ left: IntExpr{10} right: IntExpr{3} } } println(evaluate(expr)) // 5 + (10 - 3) = 12 }

🔌 C Interop & Hot Reload

🎯 Seamless C Integration

Call C libraries directly. Hot code reload for rapid development.

module main // Import C standard library #flag -lm #include fn C.sqrt(x f64) f64 // Import custom C function #flag -lSDL2 #include fn C.SDL_Init(flags u32) int fn C.SDL_Quit() // C structs struct C.SDL_Window fn C.SDL_CreateWindow(title &u8, x int, y int, w int, h int, flags u32) &C.SDL_Window // V function calling C fn main() { // Math library println(C.sqrt(144.0)) // SDL example if C.SDL_Init(0x20) != 0 { println("SDL init failed") return } defer { C.SDL_Quit() } println("SDL initialized") // Inline C $if !js { $emit("printf(\"Inline C works!\\n\");") } } // Hot reload example (live coding) [live] fn live_update() { println("This function can be updated at runtime!") } // Use hot reload flag: v -live main.v fn main_live() { for { live_update() time.sleep(1 * time.second) } }

🌐 Web & GUI Development

🎯 Full-Stack Capabilities

Built-in web server, UI framework, and cross-platform GUI development.

module main import vweb import ui // Web server example struct App { vweb.Context } fn (mut app App) index() vweb.Result { return app.html("

Hello from V!

") } fn (mut app App) user(id string) vweb.Result { return app.text("User: $id") } fn web_server() { mut app := &App{} vweb.run(app, 8080) } // GUI example struct Window { ui.Window mut: counter int } fn (mut window Window) on_button_click() { window.counter++ window.ui.label(1).set_text("Clicked: ${window.counter}") } fn gui_example() { window := ui.window( width: 400 height: 300 title: "V GUI" children: [ ui.row( children: [ ui.button( text: "Click me" onclick: fn (b &ui.Button) { println("Button clicked!") } ), ui.label(text: "Hello V UI") ] ) ] ) ui.run(window) } // HTTP client import net.http fn fetch_data() { resp := http.get("https://api.github.com") or { println("Error: $err") return } println(resp.text) } fn main() { println("V for web and GUI") // Uncomment to run: // go web_server() // go gui_example() }