Introducing the V Tutorial!
Wumi4 (460)

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!

Installation

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 https://github.com/vlang/v
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!")

f

Comments

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

Functions

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) int {
    mut total := 0
    for arg in a {
        total += arg
    }
    return total
}
println(sum())    // 0
println(sum(1))   // 1
println(sum(6,9)) // 15

Variables

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 =.

Types

Strings

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"

Numbers

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

Arrays

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

Maps

// 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)

Modules

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'

Aliasing

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

import my_game as our_game

Statements and expressions

If

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"

For

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)
}

Match

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(user.name) // "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

Closing

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
programmeruser (441)
yay -S git make patch

Aren't these packages in the official repos? Or maybe I'm just talking about the wrong distro.

Wumi4 (460)

@programmeruser 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.

programmeruser (441)

@Wumi4 oh, I thought you were using Arch Linux, which has an official repo with packages that can be installed with pacman and the AUR with yay.