Hubbry Logo
V (programming language)V (programming language)Main
Open search
V (programming language)
Community hub
V (programming language)
logo
8 pages, 0 posts
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
V (programming language)
V (programming language)
from Wikipedia
V
A capitalized letter V colored blue
The official V logo
ParadigmsMulti-paradigm: functional, imperative, structured, concurrent
Designed byAlexander Medvednikov[1]
First appeared20 June 2019; 6 years ago (2019-06-20)[2]
Stable release
0.4.12[3] Edit this on Wikidata / September 19, 2025; 60 days ago (September 19, 2025)
Typing disciplinestatic, strong, inferred
Memory managementoptional (automatic or manual)
Implementation languageV
OSLinux, macOS, Windows, FreeBSD, OpenBSD, NetBSD, DragonflyBSD, Solaris
LicenseMIT
Filename extensions.v, .vsh
Websitevlang.io
Influenced by
Go, Kotlin, Oberon, Python, Rust, Swift

V, also known as vlang, is an in-development statically typed, compiled programming language created by Alexander Medvednikov in early 2019.[4] It was inspired by Go, and other programming languages including Oberon, Swift, and Rust.[5][6][7] It is free and open-source software released under the MIT License, and currently in beta.[8]

The goals of V include ease of use, readability, and maintainability.[9][10][11]

History

[edit]

The new language was created as a result of frustration with existing languages being used for personal projects.[12] It was originally intended for personal use, [12] but after being mentioned publicly and increasing interest, it was decided to make it public.[13] V was initially created to develop a desktop messaging client named Volt.[6] On public release, the compiler was written in V, and could compile itself.[4][12] Key design goals in creating V were being easy to learn and use, higher readability, fast compiling, increased safety, efficient development, cross-platform usability, improved C interoperability, better error handling, modern features, and more maintainable software.[14][15][10][16]

V is actively being developed, maintained, and released through GitHub[17][6] by developers and contributors internationally.[4] In 2025, V became among the languages that have been listed on TIOBE index.[18]

Veasel is the official mascot of the V programming language[19]

Features

[edit]

Safety

[edit]

V has policies to facilitate memory-safety, speed, and secure code,[14][20][6] including various default features for greater program safety.[7][14][12] It employs bounds checking, to guard against out of bounds use of variables. Option/result types are used, where the option data type (?) can be represented by none (among possible choices) and the result type (!) can handle any returned errors. To ensure greater safety, error checking is mandatory. By default, the following are immutable: variables, structs, and function arguments. This includes string values are immutable, so elements cannot be mutated. Other protections, which are the default for the language, are: no use of undefined values, variable shadowing, null pointers (unless marked as unsafe), or global variables (unless enabled via flag).

Performance

[edit]

V uses value types and string buffers to reduce memory allocations.[21][22][14] The language can be compiled to human-readable C,[7][4] and in terms of execution and compilation, it's considered to be as performant.[14][15][12]

Memory management

[edit]

V supports 4 memory management options:[23][6][12][4]

  1. Use of an optional garbage collection (GC), that can be disabled, for handling allocations, and is the default.
  2. Manual memory management via disabling the GC (-gc none).
  3. Autofree, which is experimental, for invoking the necessary calls to automatically free up objects during compilation (-autofree).
  4. Arena allocation (-prealloc).

Source code translators

[edit]

V supports a source-to-source compiler (transpiler) and can translate C code into V.[15][24][10]

Working translators are also being developed for Go, JavaScript, and WebAssembly.[25][26][4]

Syntax

[edit]

Hello world

[edit]

The "Hello, World!" program in V:[14][27]

fn main() {
	println("Hello, World!")
}

Variables

[edit]

Variables are immutable by default and are defined using := and a value. Use the mut reserved word (keyword) to make them mutable. Mutable variables can be assigned to using =:[28][27]

x := 1
mut y := 2
y = 3

Redeclaring a variable, whether in an inner scope or in the same scope, is not allowed:[28][27]

x := 1
{
    x := 3 // error: redefinition of x
}
x := 2 // error: redefinition of x

Structs

[edit]

Struct example:[9][7][27]

struct Foo {
    number int
	name string
    score f32
}

// Struct fields can be initialized by name
var1 := Foo {
    number: 21
    name: "baz"
    score: 2.5
}

// or by position
var2 := Foo{50, "taz", 3.14}

Heap structs

[edit]

By default, structs are allocated on the stack. When structs are referenced by using the prefix & or have the [heap] attribute, they are allocated on the heap instead:[4][27]

struct Foo {
    number int
}

@[heap]
struct Baz {
    number f32
}

// Structs that are referenced are heap allocated
var1 := &Foo{2}

// Baz is always heap allocated because of its [heap] attribute
var2 := Baz{4.5}

Methods

[edit]

Methods in V are functions defined with a receiver argument. The receiver appears in its own argument list between the fn keyword and the method name. Methods must be in the same module as the receiver type.

The enrolled_status method (below) has a receiver of type Client named x. The convention is not to use receiver names like self or this, but preferably a short name. For example:[9][10][27]

struct Client {
    enrolled bool
}

fn (x Client) enrolled_status() bool {
    return x.enrolled
}

println(Client{enrolled: true}.enrolled_status())  // true
println(Client{enrolled: false}.enrolled_status()) // false

Error handling

[edit]

Result types may represent an error returned from a function. Result types are declared by prepending !: !Type

Optional types may represent none. Option types prepend ? to the type name: ?Type.[9][7][23][27]

fn something(t string) !string {
	if t == "foo" { return "foo" }
	return error("invalid")
}

x := something("foo") or { "default" } // x will be "foo"
y := something("baz") or { "default" } // y will be "default"
z := something("baz") or { panic("{err}") } // z will exit with an error

println(x)
println(y)

See also

[edit]

References

[edit]

Bibliography

[edit]

Further reading

[edit]
[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
V (also known as Vlang) is a statically typed, compiled programming language designed for simplicity, speed, safety, and maintainability in software development. Created by Alexander Medvednikov, it first appeared in 2019 as an open-source project aiming to enable developers to build efficient programs across domains like systems programming, web development, game development, GUI applications, and embedded systems. V emphasizes minimalism with a small set of keywords and a single enforced coding style via its vfmt tool, making it learnable in a short time—often cited as a weekend for basics. Key features of V include exceptionally fast compilation, achieving around to 500,000 lines of code per second depending on the backend ( or TCC), and performance comparable to by generating optimized, human-readable code as an intermediate step. It supports flexible , defaulting to a tracing garbage collector but offering experimental autofree for automatic deallocation without leaks, manual modes, or arena allocation to minimize runtime overhead. is prioritized through features like optional array bounds checking, immutability by default, use of Option types to handle potential null values safely, and no global variables, reducing common errors while maintaining control for performance-critical code. V provides seamless interoperability with , including automatic translation of C code to V, hot code reloading for development, and built-in libraries for web frameworks (Veb), ORM, UI (V UI), , and cross-platform support including and backends. Influenced by Go (with about 80% syntactic overlap but improvements in areas like generics and error handling), V compiles to small native binaries—such as a 250 KB —and avoids unnecessary allocations through value types and string buffers. As of 2025, V remains in pre-1.0 development, with ongoing enhancements to stability and features, though it is already used for production tools and prototyping due to its balance of expressiveness and efficiency.

Overview

Introduction

V is a statically typed, compiled, multi-paradigm programming language designed for developing maintainable software. Created by Alexander Medvednikov, it first appeared publicly on June 20, 2019, and is released under the . The language emphasizes simplicity and readability, with the goal of being learnable in a single weekend while enabling fast, safe code production across various domains such as , , and game development. V draws influences from several modern and classic languages, including Go for its concurrency model and overall structure (sharing approximately 80% similarity), for modularity, and Swift for safety features, Kotlin for expressiveness, and Python for clean syntax. As of November 2025, the stable release is version 0.4.12, with weekly development releases providing ongoing updates. The project's official website is vlang.io, and it is actively maintained on GitHub with regular updates and community contributions. V prioritizes performance and memory safety with a default tracing garbage collector, along with alternatives like experimental autofree for automatic deallocation, making it suitable for high-efficiency applications.

Design Philosophy

The V programming language was designed with a core philosophy centered on , enabling developers to produce clear and maintainable through minimal abstractions and a limited set of language constructs. This approach emphasizes and ease of learning, allowing the entire language to be grasped in a single weekend via concise , while enforcing a single idiomatic way to accomplish most tasks to reduce cognitive overhead. Influenced by Go's focus on straightforward syntax, V rejects overly complex features such as exceptions and traditional object-oriented in favor of structs and interfaces, prioritizing developer productivity without unnecessary boilerplate. A key principle is the promotion of safety and performance using a default tracing garbage collector, with experimental compile-time memory management techniques like autofree to automate deallocation for many objects, minimizing runtime overhead and potential leaks. Immutability is enforced by default for variables and function arguments—requiring explicit marking with mut for modification—to prevent common bugs like unintended state changes, while value types further reduce allocations and enhance predictability. Early versions deliberately omitted advanced features like full generics to maintain this simplicity, though they were later introduced in a restrained form to avoid complicating the core language. V aims to be production-ready from its inception, featuring a self-hosting written in V itself that generates human-readable C code for easy and optimization, compiling large projects in under a second. This includes support for hot code reloading to accelerate development cycles without full recompilation. The language's creator, Alexander Medvednikov, was motivated by frustrations with existing languages that failed to balance speed, safety, and simplicity, particularly when building projects like the lightweight Volt messaging client, which required efficient cross-platform tools without the pitfalls of languages like or the verbosity of others.

History

Origins and Development

The V programming language was created by Alexander Medvednikov, a software developer, in early 2019 as a response to the limitations he encountered in languages like Go and C while building Volt, a lightweight desktop messaging application. Medvednikov aimed to design a tool that combined the simplicity of Go with enhanced performance and safety features suitable for systems-level programming and cross-platform apps like Volt, which targeted minimal binary sizes around 300 KB. Initial development occurred privately, with Medvednikov working on the language's core before its public reveal. On June 20, 2019, an build of a self-compiling was announced, marking the language's debut and showcasing its ability to bootstrap itself without external dependencies. This highlighted V's foundational goal of rapid compilation, promising to process up to 1 million lines of code per second per CPU core, enabling full project builds in under 1 second even for large codebases. At launch, V emphasized ambitious targets including executables under 1 MB, a complete feature set expressed in straightforward syntax, and seamless with code to ease adoption for existing projects. Development remained primarily led by Medvednikov, transitioning from closed-source efforts to an open-source model under the just two days later on June 22, 2019, hosted on to invite community contributions. In its initial alpha stage, V concentrated on a stable core and a basic , prioritizing essential functionality like and simple module support while deferring advanced libraries and optimizations. This focused approach allowed early experimentation with V's self-hosting capabilities, compiling the language's own codebase in under 1 second using a C backend.

Releases and Milestones

The V programming language was publicly released on June 20, 2019, with version 0.1, marking its initial open-source availability on . This early version introduced core features like its C backend for compilation, emphasizing simplicity and performance, though it remained in alpha with ongoing development. Subsequent minor releases in 2019 and 2020, such as 0.1.24 and 0.2 series, focused on stabilizing the and expanding modules, with the C backend receiving iterative enhancements for better code generation and interoperability. By June 30, 2022, V reached version 0.3, achieving beta-like stability with improved reliability for production experimentation, as noted in community discussions and release announcements. This milestone included refinements to memory management and error handling, reducing breaking changes and enabling more consistent builds across platforms. Key achievements around this period encompassed the maturation of the C backend, which had been incrementally bolstered since 2020 through pull requests addressing codegen issues and optimization. In 2023, experimental translators emerged, including a JavaScript backend integrated into version 0.4 (released June 29, 2023), allowing V code to be output as JS for web applications, though marked as work-in-progress. A third-party V-to-Go translator also gained traction that year, facilitating interoperability with Go ecosystems on an experimental basis. V entered the TIOBE Programming Community Index in 2025, debuting at position 43 in April and reaching #41 by November with a 0.16% rating, reflecting growing search interest and adoption metrics. The most recent stable release, 0.4.12 on September 19, 2025, incorporated over 350 improvements, including autofree fixes for option arrays and return variables, alongside a 70% faster encoder surpassing prior implementations. These updates enhanced without full production readiness for autofree, which remains experimental. Looking ahead, the V team plans a 1.0 release following the 0.4 series, instituting a syntax freeze akin to Go's post-1.0 stability model to prioritize , bug fixes, and performance over new features. This approach aims to solidify the language after years of evolution. However, certain features like full native support, initially targeted for completion by late 2019, have faced delays; current implementations rely on bridging, with native backend still in planning.

Features

Safety

V emphasizes safety through a combination of compile-time guarantees and runtime checks designed to prevent common programming errors, promoting reliable and maintainable code. By default, the language enforces memory safety and eliminates many sources of undefined behavior, drawing from influences like Rust and Go while maintaining simplicity. This approach includes static typing for type safety, value semantics to avoid aliasing issues, and explicit handling of potential failures without hidden control flow mechanisms such as exceptions. One core safety feature is bounds checking on and slices, which is enabled by default to prevent out-of-bounds access that could lead to corruption or crashes. Developers can disable these checks in specific contexts, such as using the @[direct_array_access] attribute for performance-critical code or within unsafe blocks for low-level operations, but such opt-outs require explicit intent and are discouraged for general use. This mechanism ensures that array operations are verified at runtime unless explicitly bypassed, reducing the risk of buffer overflows. Variables in V are immutable by default when declared with :=, requiring the mut keyword for explicit mutability to prevent unintended modifications and side effects. This immutability extends to function arguments, which are passed by value or but treated as read-only unless marked mutable, fostering predictable behavior and easier reasoning about code. Combined with value semantics, where data is copied rather than shared via references by default, this design minimizes bugs and enhances without locks in many cases. To handle the absence of values without null pointers—which are prohibited in safe code—V uses option types prefixed with ? (e.g., ?string) to explicitly represent possible none states, forcing developers to check for presence via or or {} blocks. This eliminates null dereference errors, a common source of runtime failures in other languages. Similarly, result types for functions returning errors promote explicit error propagation, ensuring failures are addressed rather than silently ignored. V's static provides compile-time checks for , catching mismatches and invalid operations before runtime. Arithmetic operations include safeguards against overflow, with optional runtime checks against available (via the -check-overflow flag) to prevent wrapping behavior, though disabled by default for performance. By avoiding hidden —such as through exceptions or implicit conversions—the language ensures all execution paths are visible and verifiable at , further reducing surprises in program behavior.

Performance

V achieves exceptionally fast compilation speeds, primarily due to its design that generates readable C code as an intermediate representation, allowing further optimization by mature C compilers like GCC or Clang. V compiles approximately 80,000 (Clang backend) to 400,000 (x64 and TCC backends) lines of code per second on modern hardware such as an Apple M2 without optimization, as demonstrated in benchmarks. For instance, compiling a 400,000-line program consisting of repetitive assignments and print statements takes about 0.6 seconds on standard setups, outperforming languages like C (5.2 seconds with GCC) and C++ (over 1 minute with G++). Recent self-compilation tests of the V compiler itself (around 130,000 lines) complete in under 1.5 seconds on low-end hardware like an AWS t2.micro instance, equating to roughly 115,000 lines per second, with desktop machines achieving 2-3 times faster rates. At runtime, V emphasizes efficiency through value types, which pass data by value rather than , thereby reducing heap allocations and minimizing garbage collection pressure in performance-critical sections. handling further optimizes execution by using internal buffers to avoid unnecessary copying during operations like or manipulation, contributing to low-latency processing in scenarios. The language supports optional features, such as array bounds checking, that can be disabled in production builds to eliminate runtime overhead, while inline assembly allows direct integration of optimized for hotspots. Additionally, V's minimal runtime—enabled by an optional tracing garbage collector that can be fully disabled (-gc none flag)—ensures negligible overhead compared to bare C, targeting executables with a low , such as 250 KB for a basic binary. Benchmarks indicate that V's runtime performance is comparable to C for many systems-level tasks, with execution times comparable to C in tasks like nbody (within ~10%) and slightly slower in nsieve (~12-25%), but significantly slower in others like spectral-norm (up to 6x), highlighting suitability for many but not all high-performance scenarios. Independent tests across various inputs show V executables achieving similar wall-clock times to C in simple I/O and computation benchmarks, underscoring its suitability for high-performance applications. Hot code reloading, implemented via dynamic library updates, enables sub-second rebuilds during development, facilitating rapid iteration without full recompilation and thus indirectly boosting productivity in performance tuning workflows.

Memory Management

V employs four primary approaches to memory management, prioritizing performance and safety through compile-time analysis where possible. The default method is a minimal tracing garbage collector (GC) that handles automatic memory deallocation for heap-allocated objects, designed to incur low overhead during typical program execution. This GC is well-suited for general-purpose applications but can be disabled or supplemented for scenarios requiring finer control. Autofree represents an experimental alternative, enabled via the -autofree compiler flag, which automatically inserts calls to a free() function for approximately 90-100% of allocated objects at the end of their scope, mimicking (RAII) patterns from languages like C++. In this mode, the performs static analysis to track object lifetimes and generate deallocation code without runtime overhead from or full GC pauses; any remaining objects, such as those in cycles, fall back to the tracing GC. Developers can define custom free() methods for user-defined types to ensure proper cleanup of resources like file handles. As of 2025, autofree remains a work-in-progress feature, not yet production-ready or the default, with stabilization planned for V 1.0 to enable zero-GC execution in most cases. For scenarios demanding explicit control, is available by compiling with -gc none or using the [manualfree] attribute on specific functions, allowing developers to invoke new() for allocation and free() for deallocation directly. Arena allocation, activated via -prealloc, provides an efficient bulk allocation strategy using preallocated buffers, particularly beneficial for short-lived objects like small strings, minimizing fragmentation and allocation frequency. V favors stack allocation for value types whenever possible, offering zero-overhead access and automatic invalidation upon scope exit, which enhances by avoiding heap involvement. Heap allocation is reserved for dynamic needs and can be explicitly triggered using the [heap] attribute on structs or reference operators like & in certain contexts, ensuring objects persist beyond the allocating scope. The language's ownership model treats as borrowed rather than owned, with compile-time tracking of to enforce validity rules and prevent dangling pointers; attempts to reference invalid stack objects result in compilation errors, while heap references require explicit marking or unsafe blocks to bypass checks. This approach guarantees no dangling pointers in safe code, leveraging the compiler's inference to maintain without runtime costs.

Compilation and Interoperability

V's primary compilation backend transposes source code into human-readable C code, which is subsequently compiled into machine code using external C compilers such as Clang or GCC. This approach leverages the maturity and optimization capabilities of established C toolchains while enabling V's distinctive features like safety checks and metaprogramming to be enforced during the transpilation phase. The generated C code is designed to be straightforward and idiomatic, facilitating debugging and integration with existing C ecosystems. To facilitate interoperability, V includes a dedicated (FFI) mechanism through extern blocks, allowing direct calls to functions from C libraries without manual wrappers. Developers declare external C functions within an extern block, specifying the library via attributes like #[link(lib)], enabling seamless invocation of C APIs while maintaining V's for parameters and return values. This FFI support extends to embedding V code within C projects or vice versa, promoting reuse of vast C libraries in V applications. V provides tools for porting existing C codebases via a source code translator known as C2V, which converts C (and partially C++) into equivalent V code to ease library migration and modernization. This translator parses C abstract syntax trees using and generates idiomatic V equivalents, including wrappers for complex structures, thereby allowing developers to incrementally refactor C projects into V while preserving functionality. Experimental backends further expand interoperability options, including transpilation to Go for server-side applications, JavaScript for client-side scripting, and for browser or embedded environments, though these remain in early development and are not yet production-ready. Cross-compilation is a core feature, supporting out-of-the-box targeting of major platforms including Windows, , macOS, Android, and through simple command-line flags like v -os windows. No additional toolchain setup is required, as V handles platform-specific configurations during the C code generation phase, enabling rapid deployment across diverse architectures such as x86_64, ARM64, and others. The V compiler itself is self-hosting, implemented primarily in V with a C bootstrap phase for initial builds, allowing it to compile its own source code in under one second on modern hardware. This self-hosting design ensures the language's evolves in tandem with its features, with the bootstrap process using the C backend to produce a native V compiler executable.

Syntax

Basic Syntax

The basic syntax of V emphasizes simplicity and readability, aligning with the language's design philosophy of minimal boilerplate for maintainable code. A typical V program starts with the main function as the , declared using the fn keyword, followed by a block delimited by curly braces {}. For example, the canonical "Hello World" program is:

v

fn main() { println('Hello World') }

fn main() { println('Hello World') }

This code compiles and executes to output "Hello World" to the console, where println is a built-in function from the . In single-file programs, the fn main() declaration can be omitted, allowing top-level statements to run directly, which further reduces boilerplate. V's module structure organizes code into modules, with statements placed at the top of the file to access external functionality. For instance, [import](/page/Import) math imports the math module for use within the program. The default module is named main if not specified, and multiple .v files in a directory can belong to the same module, all compiled into a single . The main module contains the and can reference imported modules via their names, such as math.pi. Comments in V support both single-line and multi-line formats for . Single-line comments begin with // and extend to the end of the line, as in // This is a comment. Multi-line comments are enclosed in /* and */, and they can nest, for example:

/* This is a multi-line comment. It can contain nested comments like /* this */. */

/* This is a multi-line comment. It can contain nested comments like /* this */. */

V relies on newlines to separate statements, with no semicolons required for termination, though they can optionally separate multiple statements on a single line within expressions or blocks. Blocks are explicitly delimited by curly braces rather than indentation, but consistent use of tabs or spaces (typically 4 spaces) is recommended for in code style. String literals in V are enclosed in single (') or double (") quotes, with the formatter vfmt preferring single quotes unless a single quote appears inside the string. Both support UTF-8 encoding and escape sequences like \n for newlines. Raw strings, prefixed with r, treat backslashes literally without processing escapes, as in r'hello\nworld' which outputs "hello\nworld" unchanged.

Data Types

V provides a set of primitive data types that form the foundation for handling basic values in programs, emphasizing simplicity and explicit sizing for portability. The integer types include int, which is a signed 32-bit integer, distinct from platform-dependent sizes in languages like C or Go. Fixed-size signed integers are available as i8, i16, i32 (aliased by int), and i64, while unsigned variants are u8, u16, u32, and u64. Floating-point types consist of f32 for 32-bit precision and f64 for 64-bit precision. The bool type represents boolean values, either true or false. Strings are UTF-8 encoded sequences of bytes, declared as string and immutable by default, such as s := 'hello 🌎'. The rune type, an alias for u32, stores individual UTF-32 Unicode code points, for example, rocket := 🚀``. Variables in V are declared using the := operator, which simultaneously declares and initializes them, ensuring every variable has an initial value. By default, variables are immutable, aligning with V's emphasis on by preventing unintended modifications. To make a variable mutable, the mut keyword is prefixed, as in mut s := 'hello', allowing reassignment later. Immutability as the default promotes safer code, as explored in the Safety section. Arrays in V support both fixed and dynamic sizing. Fixed arrays have a constant and are stack-allocated, initialized like mut fnums := {{grok:render&&&type=render_inline_citation&&&citation_id=3&&&citation_type=wikipedia}}int{1, 2, 3}, where the capacity matches the . Dynamic arrays, declared with []Type, are resizable and heap-allocated, such as mut nums := [1, 2, 3], and can grow using operators like << for appending elements. Properties like len for the number of elements and cap for allocated capacity provide runtime information. Basic control structures in V enable straightforward flow control over data. The if/else construct handles conditional branching, for instance:

v

if x > 0 { println('positive') } else { println('non-positive') }

if x > 0 { println('positive') } else { println('non-positive') }

For iteration, for loops support C-style initialization, condition, and increment, as in for i := 0; i < 5; i++ { println(i) }, or range-based iteration like for i in 0..5 { println(i) }. Pattern matching is achieved via match, which compares a value against cases:

v

match x { 1 { println('one') } else { println('other') } }

match x { 1 { println('one') } else { println('other') } }

These structures facilitate concise manipulation of typed data. V employs type inference to deduce types from initializer expressions, reducing boilerplate; for example, a := 123 infers int, while b := 14.7 infers f64. Type aliases allow renaming existing types for clarity or convenience, declared as type MyInt = int, enabling MyInt to be used interchangeably with int throughout the code.

Structures and Methods

In V, structures, known as structs, provide a mechanism for aggregating related data into composite types, enabling the creation of user-defined data types that encapsulate multiple fields. A struct is defined using the struct keyword followed by the name and a block containing field declarations, where each field specifies a type. For example:

v

struct Point { x int y int }

struct Point { x int y int }

By default, struct fields are private and immutable, meaning they are accessible only within the same module and cannot be modified after initialization. Visibility can be made public with the pub modifier, and mutability can be enabled with mut; combinations like pub mut allow public mutable access limited to the parent module. This design promotes encapsulation while allowing controlled exposure of data. Struct instances can be allocated on the stack or the heap. Stack allocation occurs by default for local variables that do not escape their scope, using struct literals such as p := Point{10, 20}. For heap allocation, which is necessary when the struct's lifetime extends beyond the current function or for dynamic use, the address-of operator & is prefixed to the literal, resulting in a pointer type: mut p := &Point{10, 20}. V does not provide a built-in new constructor; heap allocation is handled explicitly via & or compiler-inferred when references escape. Structs are value types, which supports efficient passing by value without implicit copying in many cases, aligning with V's emphasis on performance. Methods in V attach behavior to structs, allowing functions to operate on struct instances as receivers. A method is declared with the fn keyword, specifying the receiver in parentheses before the method name and parameters. The receiver can be a value (a Address) for copy semantics or a pointer (&geo Geo) to enable mutation without copying the entire struct. For instance:

v

fn (p Point) manhattan(other Point) int { return int(math.abs(p.x - other.x) + math.abs(p.y - other.y)) }

fn (p Point) manhattan(other Point) int { return int(math.abs(p.x - other.x) + math.abs(p.y - other.y)) }

This method can then be invoked as p.manhattan(q), where the receiver determines whether the operation modifies the original or works on a copy. Methods promote object-like behavior without full object-oriented inheritance, focusing on composition over classical OOP hierarchies. V supports polymorphism through interfaces, which define a contract of methods and fields that types can satisfy implicitly. An interface is explicitly declared with the interface keyword, listing required methods and optional fields:

v

interface Speaker { speak() string }

interface Speaker { speak() string }

Any struct that provides all specified methods automatically implements the interface without an explicit implements clause, enabling duck typing. For example, a Dog struct with a speak() method can be used wherever Speaker is expected, such as in heterogeneous collections: mut animals := []Speaker{}. This implicit satisfaction simplifies code while ensuring type safety at compile time. Optional explicit implementation can be noted with implements for documentation. Dynamic type checking is available via is assertions, like if animal is Dog { ... }. Embedding facilitates struct composition, allowing one struct to include another as an anonymous field, thereby inheriting its fields and methods without traditional inheritance. The embedded struct's name is placed directly in the embedding struct's field list:

v

struct Size { width int height int } fn (s Size) area() int { return s.width * s.height } struct Button { Size text string }

struct Size { width int height int } fn (s Size) area() int { return s.width * s.height } struct Button { Size text string }

A Button instance gains direct access to Size fields (e.g., button.width) and methods (e.g., button.area()), promoting reusable components through delegation rather than deep inheritance trees. This approach encourages flat, composable designs.

Error Handling

V employs explicit error handling integrated into its type system, eschewing traditional exceptions in favor of result and option types to ensure errors are addressed at compile time or explicitly propagated. Functions that may fail return a result type denoted by !Type, where Type is the expected successful output, or an error otherwise. For instance, a function reading a file might be declared as fn read_file(path string) !string { ... }, returning either the file contents as a string or an error. Error propagation occurs by postfixing the function call with !, which unwraps the result and passes any error up the call stack without additional boilerplate. This syntactic sugar simplifies chaining operations while enforcing handling; if unaddressed, the compiler requires explicit management. An example demonstrates this: fn process_url(url string) !string { content := http.get(url)! return content }, where an HTTP failure propagates the error to process_url's caller. If propagation reaches the main() function without handling, V automatically panics, printing the error and exiting with code 1. Complementing result types, option types marked as ?Type handle cases of potential absence, such as nil or none values, without conflating them with errors. A function might return ?User to indicate a user object or none if not found, as in fn find_user(id int) ?User { if id == 0 { return none } user := User{id: id} return user }. Propagation for options uses the postfix ?, e.g., body := http.get(url)?.body, which unwraps the option and propagates none upward, again panicking in main() if unresolved. Developers can explicitly return none using return none or handle it with empty braces {} in certain contexts for clarity. This distinction promotes safety by preventing null pointer issues at compile time, aligning with V's emphasis on explicit null handling. Both result and option types are handled uniformly via or blocks, which provide flexible recovery strategies such as early returns, defaults, or logging. For example: user := find_user(7) or { println('User not found: ${err}') return }, where err binds the error or none value inside the block. This approach allows concise error flows, like data := read_file('config.txt') or { 'default config' }, assigning a fallback on failure. Unhandled cases in or blocks can trigger custom logic, including panics for unrecoverable states. Custom errors extend the base mechanism by implementing the IError interface, requiring a msg() string method for error description and optionally code() int for categorization. V provides a built-in Error struct that can be embedded for default behavior. A practical implementation might define:

v

struct DbError { Error query string } fn (e DbError) msg() string { return 'Database query failed: ${e.query}' } fn execute_query(q string) ! { // Simulate failure return DbError{query: q} }

struct DbError { Error query string } fn (e DbError) msg() string { return 'Database query failed: ${e.query}' } fn execute_query(q string) ! { // Simulate failure return DbError{query: q} }

Usage then integrates seamlessly: execute_query('SELECT * FROM users') or { println(err.msg()) }, outputting the custom message. This enables domain-specific error types while maintaining type safety and propagation. For truly unrecoverable conditions, V offers panic(expr), which prints the expression (typically an error) to stderr and terminates the program with exit code 1, bypassing further execution. This is invoked explicitly in or blocks or as a last resort, e.g., unsafe_operation() or { panic('Critical failure: ${err}') }, ensuring developers distinguish recoverable errors from fatal ones without implicit exception unwinding.

Standard Library

Core Modules

The core modules in V's standard library provide foundational utilities for common programming tasks, such as operating system interactions, mathematical computations, time handling, and string conversions, enabling developers to build applications without external dependencies. These modules are part of vlib, V's built-in library, and are designed for simplicity and performance, with functions that are OS-independent where possible. Approximately 20 core modules focus on everyday utilities, including os for file and process management, math for numerical operations, time for date and duration handling, strconv for type conversions, and others like strings, arrays, maps, rand, json, base64, csv, bits, benchmark, crypto, http, log, flag, and term. The os module offers platform-independent functions for file I/O, process execution, and environment variable management. For file I/O, it includes os.read_file(path string) !string to read file contents, as in content := os.read_file('path.v') or { return }, and os.write_file(path string, text string) ! to write or overwrite files. Process execution is handled by os.execute(cmd string) Result, which runs a command and captures output, while environment variables are accessed via os.getenv(key string) string and set with os.setenv(name string, value string, overwrite bool) int. V's math module supplies essential mathematical constants and functions for trigonometry, logarithms, and basic operations, emphasizing precision with floating-point arithmetic. Key constants include pi (3.141592653589793) and e (2.718281828459045), while functions cover math.sin(a f64) f64 and math.cos(a f64) f64, for example, math.cos(0) == 1.0. It also provides utilities like math.abs(x f64) f64 for absolute values and supports fixed-point-like precision through f64 operations, though random number generation is delegated to the separate rand module. The time module facilitates working with timestamps, durations, and delays, supporting standard formats for parsing and formatting. Timestamps are obtained via time.now() for local time or time.utc() for UTC, with parsing methods like time.parse_iso8601(str string) !Time and formatting such as t.format() string. Durations, represented as i64 nanoseconds, include methods like duration.milliseconds() i64 and arithmetic operations, while time.sleep(duration Duration) pauses execution, e.g., time.sleep(510 * time.millisecond). A stopwatch utility, time.new_stopwatch() &Stopwatch, measures elapsed time with sw.elapsed().milliseconds(). For type conversions, the strconv module handles translations between strings and numbers, with error propagation via !. Integer conversions include strconv.atoi(str string) !int (e.g., strconv.atoi('123')! == 123) and strconv.atoi64(str string) !i64, alongside unsigned variants like strconv.atou(str string) !u32. Floating-point support features strconv.f64_to_str_l(f f64) string for decimal strings with up to 18 digits, such as strconv.f64_to_str_l(123.1234567891011121) == '123.12345678910111'. Other core modules extend these basics for practical use: strings and arrays offer manipulation functions for built-in types; maps handles hash maps; rand provides pseudo-random generators; json and base64 enable data encoding/decoding; csv processes comma-separated files; bits manipulates bit arrays; benchmark aids performance testing; crypto implements block ciphers; http supports basic web protocols; log manages application logging; flag parses command-line options; and term controls terminal output. These modules import via simple syntax like import os and prioritize compile-time safety and zero runtime overhead where feasible.

Utilities

The net.http module in V provides essential client and server functionalities for building web applications. For server-side operations, it includes the listen_and_serve function, which starts an HTTP server on a specified address, typically with a default port of 9009, and supports configurable timeouts, worker pools, and the Handler interface for processing requests. An example server setup is as follows:

v

import net.http mut server := http.Server{addr: ':8080'} server.listen_and_serve()

import net.http mut server := http.Server{addr: ':8080'} server.listen_and_serve()

On the client side, functions such as get, post, put, patch, and delete enable HTTP requests with support for JSON, form data, multipart uploads, cookies, redirects, and proxy configurations, along with streaming downloads featuring progress tracking. For instance, a simple GET request retrieves and prints response body content:

v

import net.http resp := http.get('https://example.com') or { panic(err) } println(resp.body)

import net.http resp := http.get('https://example.com') or { panic(err) } println(resp.body)

The json module facilitates the encoding and decoding of V data structures to and from JSON format, leveraging struct tags for customization. Key functions include encode for compact serialization, encode_pretty for formatted output, and decode for parsing JSON into V types, with error handling for invalid inputs. Struct tags such as @[json: 'custom_name'] rename fields, @[json: '-'] omits them entirely, and @[omitempty] skips empty values during serialization. A representative example demonstrates encoding and decoding a struct with tags:

v

import json struct Employee { name string @[json: 'full_name'] age int @[omitempty] id int @[json: '-'] // omitted } emp := Employee{name: 'John Doe', age: 30} json_str := json.encode(emp) // {"full_name":"John Doe","age":30} mut decoded := json.decode(Employee, json_str) or { panic(err) }

import json struct Employee { name string @[json: 'full_name'] age int @[omitempty] id int @[json: '-'] // omitted } emp := Employee{name: 'John Doe', age: 30} json_str := json.encode(emp) // {"full_name":"John Doe","age":30} mut decoded := json.decode(Employee, json_str) or { panic(err) }

The crypto module exposes a range of cryptographic primitives, with submodules dedicated to hashing algorithms like and SHA-256, as well as random number generation. Hashing is handled through functions such as md5.sum and sha256.sum, which compute digests from byte inputs, while the crypto.rand submodule provides secure random byte generation via rand.bytes for keys or nonces. These are often used in conjunction with other submodules like hmac for message authentication. For example, computing a SHA-256 hash:

v

import crypto.sha256 hash := sha256.sum('hello world'.bytes()) println(hash.hex())

import crypto.sha256 hash := sha256.sum('hello world'.bytes()) println(hash.hex())

The term.ui module offers a framework for creating terminal-based user interfaces, supporting basic drawing operations and event handling for text-based applications. It utilizes a Context struct to manage the terminal state, with drawing functions like draw_rect for shapes and draw_text for rendering strings at specific coordinates, alongside event processing for keyboard inputs (key_down) and mouse actions (mouse_move). The module initializes via init with a configurable frame rate and runs the event loop using run. A basic example draws text in a frame loop:

v

import term.ui as tui struct App { mut: tui &tui.Context = unsafe { nil } } fn (mut app App) frame(_ voidptr) { app.tui.clear() app.tui.draw_text(24, 8, 'Hello from V!') app.tui.draw_rect(10, 10, 20, 20) } fn main() { mut app := &App{} cfg := tui.Config{frame_rate: 30, user_data: app} app.tui = tui.init(cfg) app.tui.run() or { panic(err) } }

import term.ui as tui struct App { mut: tui &tui.Context = unsafe { nil } } fn (mut app App) frame(_ voidptr) { app.tui.clear() app.tui.draw_text(24, 8, 'Hello from V!') app.tui.draw_rect(10, 10, 20, 20) } fn main() { mut app := &App{} cfg := tui.Config{frame_rate: 30, user_data: app} app.tui = tui.init(cfg) app.tui.run() or { panic(err) } }

The db.sqlite module serves as a lightweight wrapper around the SQLite embedded database engine, providing an ORM-like interface for database operations by wrapping the SQLite C library, which requires the SQLite library to be installed. It supports connection management through connect, which opens a database file, and query execution via exec for multi-row results or exec_one for single rows, including SQL statements for creating tables, inserting, selecting, updating, and deleting records. This enables straightforward embedded storage for applications. An example of connecting and querying:

v

import db.sqlite mut db := sqlite.connect('example.db') or { panic(err) } db.exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)') or { panic(err) } rows := db.exec('SELECT * FROM users') or { []db.Row{} } for row in rows { println(row.vals) } db.close()

import db.sqlite mut db := sqlite.connect('example.db') or { panic(err) } db.exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)') or { panic(err) } rows := db.exec('SELECT * FROM users') or { []db.Row{} } for row in rows { println(row.vals) } db.close()

Tools and Ecosystem

Compiler and Build Tools

The V programming language provides a suite of built-in command-line tools designed to streamline development, testing, and deployment processes, all accessible via the v executable without requiring external dependencies. The primary tool is the v command, which serves as the for translating .v source files into . It supports direct compilation to native binaries, with options like -c to generate human-readable C code as an intermediate output for further processing, and -os <target_os> for cross-compilation to platforms such as Windows or from a single host environment. For example, running v main.v produces an , while v -os windows main.v builds a Windows binary on a non-Windows system; the leverages backends like C for , as detailed in the compilation overview. Code formatting is handled by vfmt, an automatic tool that enforces a consistent style across V projects to promote readability and maintainability. Invoked as vfmt file.v for checking or vfmt -w file.v to apply changes in place, it standardizes indentation, spacing, and other conventions without altering functionality. Testing is integrated through vtest, a framework that enables unit tests directly in source files using functions prefixed with test_, such as fn test_example() { assert true }. Running v test . executes all tests in the current directory, reporting pass/fail results with optional verbose output via -v, facilitating rapid iteration during development. Documentation generation is managed by vdoc, which extracts and formats comments from V code into structured Markdown or HTML output. For instance, v doc module.v produces documentation for the specified module, including function signatures and descriptions, allowing developers to maintain self-documenting codebases without separate tools. These tools integrate seamlessly with build systems like Makefiles for complex projects, where v commands can be scripted, and with IDEs such as through official extensions that provide , autocompletion, and support via the V Language Server.

Community and Adoption

The V programming language community is primarily GitHub-based, with the official repository attracting over 35,000 stars, more than 1,800 forks, and contributions from 794 developers as of late 2025. Support and discussions largely occur through the official server, which has over 6,400 members, fostering interactions among hobbyists, early adopters, and contributors focused on libraries and documentation. The ecosystem includes a module registry at modules.vlang.io, where users share and discover packages for extending V's capabilities. Adoption of V remains niche, primarily in personal tools, games, and web applications rather than large-scale production environments. Notable examples include Volt, a lightweight 3 MB client for Slack and services; Gitly, a minimal source code management tool serving as an alternative to and ; and the web framework for building server-side applications. Other projects demonstrate its use in games like a V implementation of and utilities such as fdup for duplicate file detection. V entered the TIOBE Programming Community Index in 2025, ranking 41st with a 0.16% share, reflecting modest but growing visibility among compiled languages. Criticisms of V often center on overpromising features during its early promotion, such as ambitious claims for automatic C/C++ translation and ultra-fast compilation that have faced delays in full realization. The language's alpha-to-beta stage has led to reports of compiler instability, including bugs affecting code generation and , making it less suitable for critical production use without extensive testing. Development heavily relies on lead creator Medvednikov, though community contributions have increased, raising concerns about long-term maintainability if core progress stalls. Community feedback highlights needs for improvements like expanded , a richer , and a syntax freeze to build user confidence ahead of stable releases. Looking ahead, V's developers aspire to broader adoption following the 1.0 release, which will prioritize production-ready autofree memory management and ecosystem enhancements like native support to attract more systems and web developers.

References

Add your contribution
Related Hubs
User Avatar
No comments yet.