Skip to content
Sign upLog in

Introducing the V Tutorial!

Profile icon

Introducing the V Tutorial!

A few months ago, I've seen a project in my GitHub Trending called V. I have seen some cool things about this language, and I think that V is a very promising language! So today, I introduce you, the V tutorial! :)

But first, what's V? 🤔

V is, as it introduced:

Is a statically typed, compiled, small, and fast language, for developing maintainable software. The syntax of V is similar to Go and has been influenced by Oberon, Rust, Swift, Kotlin, and Python.

Some cool things about V 🎉

  • Simple: V is similar to Go, so if you mastered Golang, then you know at least 80% of V (at least the devs of V promises that)
  • Safety: There is no null, no global variables, no variable shadowing, immutable variables by default, no undefined behavior, and many more!
  • Performance: V is as fast as C (V's main backend compiles to human-readable C, and again, the developers promises for this, not me).
  • Plays well with C: V can translate your C project in >1s! I don't know what this is for, but if you are a C dev and wondered to move your C projects into V, well, this is useful for you!

Here is a taste of it! 😉

fn main() { languages := ["English", "Russia", "Vietnam", "Hindu"] for language in languages { println("Hello, $language talkers!") } }

Looks similar, right?

Tutorial 🥳

Now, we will go to the tutorial!

In this, I will mostly take them from the V official document and present it in a better and friendlier way (I hope), also I will reduce some stuff from the official to keep this simple. Mostly the example code are just a modified version of the code from the official doc, some are made by me (Disclaimer: Some of them can contain errors, so I would not recommend you to copy it like a zombie). If you want to learn more about V, please check out the official V documentation

Now, let's get into in!


First, we need to install the V compiler first, so we can run our V programs! We will build it from the V source code.

We need git, make and patch installed:

yay -S git make patch # Or this if you are on Arch pacman -S git make patch # Or this if you are on Ubuntu apt install git make patch

When you're done, we will start building V by cloning their GitHub repo:

git clone cd v make

And that's it! Now you have a V executable at [path to V repo]/v, and [path to V repo] can be anywhere.

Now you can try your V compiler using ./v run examples/hello_world.v

Symlinking to saving time

I highly recommended that you put your V compiler in the PATH, it saves a lot of time. V has the symlink command to make it more convenient and easier to do it.

# Make sure you are in the V repo! sudo ./v symlink

After that, you should close your shell/editor, so V can pick the new PATH variable.

Install the V compiler through an AUR helper

If you are a Manjaro user (like me), luckily, you can install the V compiler already with no need to build though an AUR helper, like yay.

yay -Syu yay -S vlang

Hello V!

We will start with the modified version of the traditional Hello world! program, Hello V!

fn main() { println("Hello V!") }

In the code, we create the entry point function (aka the main function) that will run any code inside it, in that function, we use the built-in function println() to print a string (In this case is "Hello V!")

Now, we can run our program by saving it to a file called hi_v.v and run it using v run hi_v.v. You should see the phrase Hello V! shows when it's done.

A cool thing about V is that you can skip the fn main() declaration, this is useful when you want to write small programs, or learning the language, for clarity, the fn main() declaration will be skipped in this tutorial.

That means that you can just type:

println("Hello V!")



// This is a single line comment in V /* This is a multiline comment. /* And it can be nested. */ */


fn main() { println("10 + 20 = ", add(10, 20)) } fn add(a int, b int) int { return a + b }

Like Go, the type comes after the function name and the argument's name (In case here is int, aka integers). And like Go and C, functions can't be overloaded, simplifies the code and improve maintainability and readability. Functions can be used before or after their declaration: The function add are declared after the entry point function, but can still be called from it. This is true for all declarations in V and eliminates the need for header files or thinking about the order of files and declarations like what you will deal on C++ and C.

Returning multiple values

You can return more than 1 value from a function in V!

// This function returns 2 integers fn foo() (int, int) { return 2, 3 } a, b := foo() // Assign 2 and 3 to a and b println(a) // Returns 2 println(b) // 3 c, _ := foo() // You can ignore other values using '_'

Accept multiple arguments

You can assign multiple arguments to a function, like Python's *args.

// 'a' is the '*args' in Python, but it's // name can be changed! fn sum(a int { mut total := 0 for arg in a { total += arg } return total } println(sum()) // 0 println(sum(1)) // 1 println(sum(6,9)) // 15


name := 'Isabelle' age := 18 a_large_number := i64(6942069420) println(name) println(age) println(a_large_number)

Variables are declared and initialized using :=, and this also the only way to declare and initialize a variable in V, means that the variable always have an initial value, and the variable's type is inferred by the value from the right side. If you want to change the type to another, use type conversion: T(v) changes the value v to type T, for example: int(10.2) will convert the float 10.2 to integer.

Unlike many languages, V only allows you to declare variables as functions, global variables are not allowed. Means that:

x := 10 // This is illegal. fn main() { y := 20 // But this is legal. }

All the variable and function names must be use the snake_case style to name them (e.g. hello_world). And with the type names is PascalCase (e.g. HarryPotter).

Mutable variables

mut age := 20 println("Before, I was ", age) age = 21 println("Now, I'm ", age)

In V, all the variables are immutable by default, to be able to change their value, you need to use mut. And to give a mutable variable a new value, you need to use =.



name := 'Joe Mama' println(name) // Prints "Joe Mama" println(name.len) // Prints 8 println(name[0]) // Indexing, returns J println(name[1..3]) // Slicing, returns 'oe'

Strings in V are a read-only array of bytes, and they are encoded using UTF-8. They are immutable and can't be changed.

mut closing := "kthxbye" closing[0] = 'K' // Illegal. Comment this, dev.

Like in C and Python, V also has escape characters, like \n, \t and so on.

formatted := "hello\nworld" println(formatted) // Output: // hello // world

If you want raw strings, use r, escape characters is useless to raw string.

formatted := r"hello\nworld" println(formatted) // Output: hello\nworld

String Interpolation (Embedding variables and stuff to strings)

String interpolation is simple in V - use $ after variable name, the variable will converted to string type and embedded to the string.

squid := "Squid" println("I hate $squid! >:(") // I hate Squid! >:(

If you want to do more complex expressions, use ${}.

println("10 + 20 = ${10 + 20}") // 10 + 20 = 30

String Operators

name := "Will" willy := name + "y" // + for concatenate strings println(willy) // "Willy" mut s := "Hi " s += willy // += for append to a string println(s) // "Hi Willy"


a := 123 // integer, b := 0x7B // hex, c := 0b01111011 // binary, d := 0o173 // and octal, they are all type 'int' // You can also use '_' to improve readability. num := 1_000_000 // the same as 1000000 // Float numbers. f := 1.20 f1 := f32(12.2) // Casting is possible with numbers and many types


An array is a type that contains some element with the same type, the type of the array is determined by the first element of that array, for example, [1, 2, 3] is an array of integers, because the first element, 1 is an integer. And they are immutable by default.

mut numbers := [1, 2, 3] numbers[0] = 5 // Change the first element's value to 5 println(numbers) // [5, 2, 3] println(numbers[0]) // 5 println(numbers[0..2]) // Slicing, prints [5, 2] // This prints the length of the array println(numbers.len) // 3 // This is illegal! random_types := [1, "a"] // 2 different types in one array, you broke the rules! >:(

Array operators, methods, and other things with it

mut nums := [20, 30, 40] nums << 4 // Adds 4 to the end. nums << [10, 20, 30] // Add each element in the array to the end of array println(50 in nums) // false, because 50 is not in 'nums' // ---------------- mut numbers := []int{cap: 10} // Create an empty list with the capacity of 10 for i in 1..10 { numbers << i } println(numbers) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // This creates a list with initial length is 5 // And all the element by default is 1 list_of_1s := []int{len: 5, init: 1} // [1, 1, 1, 1, 1] // --------------- // Clone an array with `.clone()` sus_list = ["Yellow", "Black"] mut updated_list = sus_list.clone() updated_list << ["White", "Pink"] println(sus_list) // ["Yellow", "Black"] println(updated_list) // ["Yellow", "Black", "White", "Pink"] // -------------- // Filtering is simple in V. data := [2, 4, 5, 6, 7, 8, 90, 10] // 'it' is a builtin variable refers to the current // element being processed in filter methods even := data.filter(it % 2 == 0) println(even) // [2, 3, 6, 8, 90, 10] // -------------- // Sorting elements in array is simple and intuitive mut unsorted := [20, 42, 56, 78, 90, 12, 8] unsorted.sort() // 8, 12, 20, 42, 56, 78, 90 unsorted.sort(a > b) // Sort in reverse way, a and b are special variables for custom sorting condition


// In V, maps are just like Python. // But the keys must be strings. mut replers_with_most_cycle = { "Coder100": 10000, "DynamicSquid": 3000, "Others that I don't remember": 69420, } println(replers_with_most_cycle["Coder100"]) println("DynamicSquid" in replers_with_most_cycle) // Delete a key is also simple replers_with_most_cycle.delete("Others that I don't remember") println("Others that I don't remember" in replers_with_most_cycle)


Import modules

To import modules in V, you use import.

import os // Import the os module. fn main() { // Read text from Stdin name := os.input("Henlo. What's your name?") println("Hi there $name!") } // -------------- // You can also import specific functions and types // from the module import crypto { sha256.sum } // Import 'sha256.sum' from 'crypto' import time { Time } // Import 'Time' from 'time'


You can also import the module name as another name to save time.

import my_game as our_game

Statements and expressions


a := 10 b := 20 if a < b { println('$a < $b') } else if a > b { println('$a > $b') } else { println('$a == $b') }

if statements are straightforward as in many languages, there is no parenthesis surrounding the condition like in C, and the braces is always required.

if can also be used as an expression, like this:

even_number := 200 the_number_is_even := if even_number % 2 == 0 { "even" } else { "odd" } println(the_number_is_even) // Prints "even"


There is only one looping keyword in V: for . There are several styles for this loop.

Array for

mut names := ["Sam", "Cookie", "KTHXBYE"] // Prints just their name for name in names { println(name) } // Prints their name and their index for index, name in names { println("$name in $index") }

Like Python, V also has the for value in arr form. It's used to, well, you guess it, going through each element in the array. And when you also need their index, then use for index, value in arr instead.

And because the value is read-only, so when you need to change their value, you have to use indexing.

mut memes := ["Joe Mama", "Eggman", "Election"] for i, _ in memes { memes[i] = "Eggman" // Change all the element to "Eggman" } println(memes)

Range for

for i in 0..5 { println(i) } // Output: // 0 // 1 // 2 // 3 // 4

The range 0..5 makes an exclusive range, means that they represent values from 0 to 4, not including 5.

Looping though a map value

m := {"Hi": 0, "Hello": 1} for key, value in m { println("$key is $value") } // Output: // Hi is 0 // Hello is 1 // And you can use `_` to ignore other values for key, _ in m { println(key) } // Output: // Hi // Hello for _, value in m { println(value) } // Output: // 0 // 1

For with condition

// The for loop in V can also acts like a while loop! // Now know why the 'while' loop is not in V? ;) mut i := 0 for i <= 100 { i += 1 println(i) } // Output: // 1 // 2 // ...

Infinite loop

If you remove all the conditions for the for loop, it will become an infinite loop, never stop.

mut i := 0 // This loop will never stop. // Until the 'if' inside it is true, it will break the // loop for { i += 1 if i >= 10 { break } } println(i) // 10

The C for style

If you don't like the modern loop style or just want your code to feel more oldschool and friendly, you can use the good old C style, it's safer than the while one, because it's easy to forget to update your values, resulting in an infinite loop.

for i := 0; i <= 10; i += 1 { // Don't print 9 if i == 9 { continue } println(i) }


number := 10 match number < 2 { true { println("Under 2.") } false { println("Larger than 2.") } }

match is another and shorter way to write a if - else statement. When a matching branch is found, it will do the code in the following statement block. The else is used when there is no matching branch. And match can be used as an expression just like if-else.

number := 12 s := match number { 1 { "One." } 2 { "Two." } else { "Many." } }

Bonus things

Decoding JSON in V

JSON is a very popular data format. Every time you need to config your workspace in VS Code, every time you need to make a config file, for your program, so the user can customize it easily, JSON is always the first. And luckily, V has supported a built-in JSON library for you!

// Importing JSON import json // To decode a string in JSON, you need a structure. struct User { name string age int birth i64 [skip] // You can use [skip] to skip certain fields job string [json: Job] // If the field name is different in JSON, in can be specified } data := '{ "name": "Joe", "age": 18, "job": "Programmer" }' // In here, json.decode requires 2 things: // - The types that JSON should decode to // - The data // That's why we need a struct // Also, the 'or' is for the case that our decoding // failed. user := json.decode(User, data) or { println("Can't not decode to JSON.") return } println( // "Joe" println(user.age) // 18 println(user.job) // "Programmer"

Builtin Functions

println() is not the only builtin function in V, there are some others builtin functions, here's a complete list:

print(s string) // Print string on stdout (the standard output) println(s string) // Same as print(), but with a newline eprint(s string) // Same as print(), but prints on stderr (the standard error output) eprintln(s string) // Same as println(), but prints on stderr exit(code int) // Exit the program with a custom error code panic(s string) // Prints a message and backtraces on stderr, then exit the program with error code 1 print_backtraces() // Print backtraces on stderr


Ok, so after this tutorial, you have learned about the V programming language, you have learned from the basics to some higher concept of it, you also learned about how to decode JSON is V (as a bonus thing). If you have any question, comment down below! 😉

Happy (Late) New Year everyone! :D

You are viewing a single comment. View All
Profile icon

Well, in my Manjaro which has its own repo, there aren't any of them! So I have to use a AUR helper, which is yay.