V, also known as vlang, is a statically typed, compiled programming language created by Alexander Medvednikov in early 2019.[4] It was inspired by the language Go, and other influences 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]
Paradigms | Multi-paradigm: functional, imperative, structured, concurrent |
---|---|
Designed by | Alexander Medvednikov[1] |
First appeared | 20 June 2019[2] |
Stable release | 0.4.5[3]
/ March 20, 2024 |
Typing discipline | static, strong, inferred |
Memory management | optional (automatic or manual) |
Implementation language | V |
Platform | x86-64 |
OS | Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD, DragonflyBSD, Solaris |
License | MIT |
Filename extensions | .v , .vsh |
Website | vlang |
Influenced by | |
Go, Kotlin, Oberon, Python, Rust, Swift |
The goals of V include ease of use, readability, and maintainability.[9][10]
According to one of the developers, the new language was created as a result of frustration with existing languages being used for personal projects.[11] The language was originally intended for personal use, but after it was mentioned publicly and gained interest, it was decided to make it public. V was initially created in order to develop a desktop messaging client known as Volt.[6] Upon public release, the compiler was written in V, and could compile itself.[4] Key design goals behind the creation of V were being easy to learn and use, higher readability, fast compilation, increased safety, efficient development, cross-platform usability, improved C interop, better error handling, modern features, and more maintainable software.[12][13][10][14]
V is released and developed through GitHub[15][6] and maintained by developers and contributors from the community.[4]
V has policies to facilitate memory-safety, speed, and secure code.[7][17] Among these default safety features are:[7][17][6][9] 1) Usage of bounds checking. 2) Usage of Option/Result. 3) Mandatory checking of errors. 4) Variables are immutable by default. 5) Structs are immutable by default. 6) Function args are immutable by default. 7) No usage of values that are undefined. 8) No shadowing of variables. 9) No usage of null (unless in code marked as unsafe). 10) No usage of global variables (unless enabled via flag).
V uses value types and string buffers to reduce memory allocations.[18][19][17]
The language's 4 supported options for memory management are the following:[20][6][21] 1) Use of an optional 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 handles most objects via free call insertion, and then the remaining percentage is freed by GC (-autofree
). 4) Arena allocation (-prealloc
).
V supports a source-to-source compiler (transpiler) and can translate C code into V.[22][23][10]
Working translators are also under development for Go, JavaScript, and WebAssembly.[24][25]
The "Hello, World!" program in V:[17]
fn main() {
println('Hello, World!')
}
Variables are immutable by default and are defined using :=
and a value. Use the mut
keyword to make them mutable. Mutable variables can be assigned to using =
:[26]
a := 1
mut b := 2
b = 3
Redeclaring a variable, whether in an inner scope or in the same scope, is not allowed:[26]
a := 1
{
a := 3 // error: redefinition of a
}
a := 2 // error: redefinition of a
Struct example:[12]
struct Point {
x int
y int
}
mut p := Point {
x: 10
y: 20
}
println(p.x) // Struct fields are accessed using a dot
// Alternative literal syntax for structs with 3 fields or fewer
p = Point{10, 20}
assert p.x == 10
Structs are allocated on the stack by default. To allocate a struct on the heap and get a reference to it, the & prefix can be used:[12]
struct Point {
x int
y int
}
p := &Point{10, 10}
// References have the same syntax for accessing fields
println(p.x)
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 is_registered method has a receiver of type User named u. The convention is not to use receiver names like self or this, but preferably a short name. For example:[9][12]
struct User {
age int
}
fn (u User) is_registered() bool {
return u.age > 16
}
user := User{
age: 10
}
println(user.is_registered()) // "false"
user2 := User{
age: 20
}
println(user2.is_registered()) // "true"
Optional types are for types which may represent none. Result types may represent an error returned from a function.
Option types are declared by prepending ? to the type name: ?Type. Result types use !: !Type.[9][7][20]
fn do_something(s string) !string {
if s == 'foo' {
return 'foo'
}
return error('invalid string')
}
a := do_something('foo') or { 'default' } // a will be 'foo'
b := do_something('bar') or { 'default' } // b will be 'default'
c := do_something('bar') or { panic("{err}") } // exits with error 'invalid string' and a traceback
println(a)
println(b)