Chapter 1: Introduction to V Programming
The V programming language is a statically typed compiled programming language that's used to build maintainable and robust software applications. It comes with high performance and simplicity, which allows software programmers to do rapid prototyping of applications at scale. You can write simple and clean code with minimal abstraction using V. V comes with performance as fast as C. V is not derived from any other programming language and is written in V itself and compiles itself in under 1 second.
The design of V has been influenced by programming languages such as Go, Rust, Oberon, Swift, Kotlin, and Python. The V language has similar syntax compared to the popular Go programming language. It is a simple, fast, safe, and compiled programming language. V offers all safety features by default, such as immutable variables, immutable structs, and pure functions. V offers great support for concurrency that is on par with Go programming.
In this chapter, we will cover the following topics:
- The past, present, and future of V
- V is a statically typed and compiled programming language
- Simple and maintainable syntax
- Backward compatibility, stability, and easy to upgrade to future versions
- Features of V programming
- V as a framework
- Operating systems V supports
By the end of this chapter, you will have learned about the V language and its features. You will also understand Vinix, an operating system (OS) written completely in V.
Let's begin our journey by understanding how V came into existence, who created it, and what its future is.
The past, present, and future of V
V is a new programming language created in early 2019 by Alexander Medvednikov. The creator has come up with an extensive vision for the V language and the features it offers. Therefore, the V language and its various features are undergoing heavy development. The official website is https://vlang.io/. The V programming language is open sourced and licensed under MIT. You can refer to the entire source code of V on its official GitHub repository at https://github.com/vlang/v.
V has an active community of developers and contributors. The community is highly active and responsive to issues raised on GitHub. You can participate in discussions at https://github.com/vlang/v/discussions and the team is also available on Discord: https://discord.gg/vlang.
V comes with a lot of performance optimizations that are on par with C compared to any other programming language, such as Go, Java, or Python to mention a few..
From version 0.3, V is expected to have the ability to translate C code to human readable V code. Also, you will be able to generate V wrappers on the top of C libraries.
V is a statically typed and compiled programming language
A programming language is designed to have certain typing and execution phenomena. Typing could refer to either statically typed or dynamically typed, while the execution phenomena could be referred to as compiled or interpreted. Let's look at these terms in more detail.
Statically typed versus dynamically typed
A programming language is referred to as statically typed when the type checking of the variables happens during compile time instead of runtime.
In a dynamically typed programming language, the types are determined during runtime based on the values assigned to the variables. The advantage of dynamically typed programming languages is that the programmers do not have to explicitly mention the type of variables while they code. This capability eases and speeds up development times.
Compiled versus interpreted languages
A programming language is said to be compiled when the code is directly translated into machine code or byte code. This phenomenon makes the resulting program run significantly faster in contrast to interpreted languages. V compiles ~1 million lines of code (LOCs) per CPU per second.
On the other hand, the term interpreted refers to programming languages where the interpreter runs the program by executing the commands line by line. And this phenomenon makes interpreted languages significantly slower than compiled languages.
The V programming language is a statically typed compiled programming language. So, the type checking in V happens during compile time itself. Also, when you build a V program, it generates an executable file as output that contains all the instructions written in the program translated into machine code.
Simple and maintainable syntax
As we've already learned, V is inspired by the Go programming language, and its design has also been influenced by Oberon, Rust, Swift, Kotlin, and Python. V comes with the simplest form of coding style when it comes to syntax and semantics. If you are a Go programmer, writing a program in V gives you an adrenaline rush because of the simplicity of the syntax. The syntactic simplicity offered by V lets beginners of this programming language learn quickly and understand the basics instead of trying to learn about the semantics.
V takes a similar or even fewer number of LOCs to mimic functionality written in Go. It has only one standard format for writing code, and this is managed by vfmt
, a built-in library that helps format the code. vfmt
strictly formats your code according to a globally unique coding standard across all V projects.
All it takes to write a simple program in V is just the following three LOCs:
fn main() { println('Hello, from V lang!') }
You don't even need fn main() {
and the closing bracket, }
. Just place the following line in a file named hello.v
and run it using the v run hello.v
command:
println('Hello, from V lang!')
In contrast to V, where we can write a simple program in just a line, a similar program written in Go, after formatting, takes at least seven LOCs, which appear as follows:
package main import "fmt" func main() { fmt.Println("Hello from Go lang!") }
As you can see, compared to the preceding code, the V program shown earlier looks concise and minimal while at the same time offering readability and avoiding a lot of unnecessary imports.
Backward compatibility, stability, and easy to upgrade to future versions
The V programming language, at the time of writing this book, is still in development. But it has evolved a lot since its inception and has received a lot of appreciation from software engineering communities across the world. This book attempts to introduce various programming features that V has already got in detail throughout this book.
Although it is noteworthy that V is still in development at the time of writing this book, beginning with version 1, it will be highly stable and also offers a backward compatibility guarantee. V's formatter, vfmt
, automatically takes care of upgrading your code for you. So, you don't have to manually identify the incompatible syntax when you upgrade your version of V.
Features of V programming
Despite being a very new and constantly evolving programming language, V has got all the most sought-after features that satisfy the needs of modern-day programmers. In this section, we will explore various features of V.
Performance
V has Clang, GCC, or MSVC as its primary backend, depending on the OS, which allows it to compile to human-readable C. Having these compilers as the main backend allows V to have easy interoperability with C. V, with its innovative memory management, performs a minimal amount of memory allocation by using value types and string buffers. A program written in V gets compiled to native binaries without any dependencies. Also, V compiles the whole application into a single binary, which makes it easy to deploy.
Speed
At the time of writing this book, according to the official website, https://vlang.io/, with a Clang backend, V compiles ~110k LOCs per second, per CPU core. With x64 and a TCC backend, V compiles ~1 million LOCs per CPU core.
No null values
A null value indicates nothing. A null value neither represents an empty nor a default value. Having null values in a programming language enforces you to handle the null scenarios using multiple checks. These checks, when missed, might lead to errors.
V does not have null or nil values, unlike other programming languages such as Java, C#, Python, or Go. This is because all the types in V are zeroed in by default. Zeroed in means that they are assigned with default values, such as an empty string for string types, 0 for integers, and false for Boolean types. Thus, V does not rely on the compiler to check whether the type is null or not, thereby preventing the program from creating several errors.
No global variables
Global variables allow you to maintain the state at the application level. Though this sounds comforting, global variables slowly lead to reliability problems that arise due to the growing number of actors on such variables.
In V, global variables are disabled by default. These global variables can be declared using the __global
keyword and running the V program with the -enable-globals
argument. The reason why V facilitates working with global variables is to allow the implementation of low-level applications such as programming OS kernels or system drivers. In such cases, you may need to have variables that can be accessed globally.
No undefined values
In V, when you declare a variable of any type, you must initialize it. Otherwise, it leads to compilation errors. Also, in the case of structs, which are detailed in Chapter 8, Structs, the fields of a struct are zeroed into their default values.
Error handling
V has a very simple approach to dealing with errors. You have the flexibility to deal with these errors using an or {}
block or let the errors propagate using the optional operator, ?
. You can also build custom errors using the built-in error method, which accepts a string as an input argument. The different ways to deal with errors will be demonstrated in the Functions can have optional return types section of Chapter 7, Functions.
Powerful concurrency
V has a very powerful concurrency framework. It is essential for an application running on a high-end computing device to be able to utilize its resources, such as its CPU cores, efficiently. Through V's built-in concurrency model, using the go
keyword, you can spawn functions to run concurrently on other threads, different from the thread where the main program runs. The functions that run concurrently are called coroutines.
You can have shared variables to synchronize the data between coroutines by enforcing read-only locks using the rlocks
keyword or read/write/modify locks using the lock
keyword. This approach is demonstrated in the Sharing data between the main thread and concurrent tasks section of Chapter 10, Concurrency. With this traditional concurrency synchronization technique, the coroutines communicate by sharing data or memory.
As creating shared variables and manually enforcing locks is often cumbersome, V has a built-in library called sync
that implements advanced concurrency patterns known as channels. A channel allows you to share data by establishing a communication channel among coroutines. A channel acts as a medium where a coroutine pushes data into it and other channels pop the data out of it. We will learn about channels, along with their features and how to work with buffered and unbuffered channels, in Chapter 11, Channels – An Advanced Concurrency Pattern.
Easy cross-compilation
V allows you to generate cross-platform binaries with its cross-platform compilation capabilities. With this feature, from a *nix OS, you can generate your application's executable that targets *nix OS variants, as well as Windows or macOS. From a *nix OS, let's say Ubuntu, create a file named hello.v
and add the following code to it:
module main fn main() { os := $if windows { 'Windows' } $else { 'Unix' } println('Hello, $os user!') }
The $
symbol in the preceding code tells the compiler to evaluate the following if
condition right away during compile time. Also, windows
is a built-in term that's used to identify the OS type.
Run the preceding code using the v run hello.v
command. You will see Hello, Unix user!
as the output.
From the *nix OS, you can run the following command to create a cross-compiled executable targeting the Windows OS.
Before you start generating a cross-compiled binary for the hello.v
program, you need to install mingw-64
, which is required to generate an executable targeting the Windows OS. To install mingw-64
, run the following command:
sudo apt install -y mingw-w64
Alternatively, you can try sudo apt install -y mingw-w64
on Debian-based distributions or sudo pacman -S mingw-w64-gcc
on Arch.
Once mingw-64
has been installed, run the following command from the Ubuntu OS to generate the executables that can run on the Windows OS, as follows:
v -os windows hello.v
The preceding command will generate an executable named hello.exe
. Now, transfer the .exe
file to the Windows OS. Running the executable from Command Prompt will output Hello, Windows user!
.
You can also cross-compile to generate *nix binaries from a Windows OS. All you need to do is install Clang for Windows, as described at https://clang.llvm.org/get_started.html, and run the following command, which generates the *nix binary:
v -os linux hello.v
Similarly, to generate an executable for macOS, run the following command:
v -os macos hello.v
V to JavaScript conversion
In addition to C as a primary backend, V also has JavaScript and WASM backends. V programs can be translated into JavaScript. To translate the hello.v
into JavaScript, you can run the following command:
v -o hello.js hello.v
It is as simple as the preceding command. The outcome will produce a JavaScript file named hello.js
that reflects the functionality written in the hello.v
program.
Profiling
V has an built-in profiling tool that you can use to analyze how your program is behaving or how many times a function gets called on average by a function per call. You might need this information to debug and optimize the application code. To run the profiler against the V program, let's say hello.v
, run the following command:
v -profile profile.txt hello.v
Notice the usage of the -profile
argument, followed by the text file. Running the preceding command generates a binary for the hello.v
program. Running the binary generates profile.txt
with a detailed list of all the function calls with three columns. Each of the columns in the text file represents the number of calls, average time per call, and total time per call.
V as a framework
With the suite of packages V comes with, it can be considered equivalent to a framework. A framework generally comprises all the features of full-blown programming, along with the ability to smoothly plug and play the external packages. Using V, you can write enterprise-grade software, even though it is still in development. In the following sections of this chapter, we will look at the various suites of libraries and features that are written and implemented using V, which will help us build robust software applications.
Memory management using the autofree engine
V offers robust memory management with automatic garbage collection capabilities. Most of the objects are freed by V's autofree engine. Starting with V version 0.3, the autofree engine is enabled by default. You can also forcefully enable the autofree engine using the -autofree
flag.
With the help of the autofree engine, the V compiler invokes the necessary calls to automatically free up objects during compilation. A small fraction of the objects is released from memory via reference counting. V also offers the ability to turn off the automatic garbage collection capability with the help of the -noautofree
flag.
Built-in ORM
It is unlikely that a programming language will be available with a built-in Object Relational Mapper (ORM ), but V is. Though the orm
library is in an alpha state at the time of writing this book, it has all the basic features, which are enough to implement data-driven applications that have relational databases as backends.
Currently, the orm
library supports SQLite, MySQL, and Postgres and has planned support for popular relational databases such as MS SQL and Oracle.
The built-in orm
eases the development time by offering you the standard V-based queries to interact with all the aforementioned relational databases. You will learn more about ORM in Chapter 13, Introduction to JSON and ORM.
Built-in web server
The vweb
web server is a built-in library. Though it is in an alpha state at the time of writing this book, it offers various features in its current state, including the following:
- Built-in routing.
- Handling parameters.
- Templating engine.
- Very fast performance, like C on the web.
- Building the project using
vweb
generates a single binary, thus simplifying deployments.
You will learn how to implement a microservice with RESTful endpoints using vweb
, along with other libraries such as orm
and json
, in Chapter 14, Building a Microservice.
Native cross-platform GUI library
V has a cross-platform ui
library. Using this library, you can leverage the power of building cross-platform GUI applications. The ui
library can be found at the official GitHub repository at https://github.com/vlang/ui, which is licensed under GPL 3.0.
V has a ui
module that uses native GUI toolkits: WinAPI/GDI+ on Windows and Cocoa on macOS. On Linux, custom drawing is used.
Vinix – an OS kernel written in V
Vinix is an effort to write a modern, fast, and useful OS using V. Vinix is purposefully built to facilitate writing low-level software.
The Vinix OS is licensed under GPL 2.0, and you can find its entire source code on its official GitHub repository at https://github.com/vlang/vinix. You can always download the latest version of the Vinix OS in the form of ISO from the official link: https://builds.vinix-os.org/repos/files/vinix/latest/vinix.iso.
Vinix aims to have the following features:
- Make a usable OS that can run on emulators, virtual machines, and physical hardware
- Target modern 64-bit architectures, CPU features, and multi-core computing
- Maintain good source-level compatibility with Linux, which helps with porting programs between Vinix and Linux
- Explore V's capabilities in bare-metal programming
- Improve the compiler in response to the uncommon needs of bare-metal programming
Operating systems V supports
The V programming language is cross-platform compliant. The V language runs on almost all the major operating systems. V runs on all versions of Windows, on all *nix variants such as CentOS, Fedora, and Ubuntu, and also on macOS. V also runs on the popular mobile OS known as Android. V runs on all the Windows OS variants where Windows Subsystem for Linux (WSL) is supported. V can also be used in the Internet of Things (IoT) as it supports running on IoT platforms such as Raspberry Pi.