V programming language

Fast, safe, compiled language created for developing Volt, soon available for everyone.

Open source release in mid 2019.
Install V from source in 0.5 seconds
wget vlang.io/v.c && gcc -o v v.c

Comparison of V and other languages

Go

V is very similar to Go, and these are the things it improves upon:

- No global state

- Only one declaration style (a := 0)

- No null

- No undefined values

- No err != nil checks (replaced by option types)

- Immutability by default

- Much stricter vfmt

- No runtime

- Much smaller binaries

- Zero cost C interop

- No GC

- Fearless concurrency (no data race guarantee at compilation)

- Generics

- Cheaper interfaces without dynamic dispatch

- Centralised package manager


Rust

Rust has a very different philosophy.

It is a complex language with a growing set of features and a steep learning curve. No doubt, once you learn and understand the language, it becomes a very powerful tool for developing safe, fast, and stable software. But the complexity is still there.

V's goal is to allow building maintainable and predictable software. That's why the language is so simple and maybe even boring for some. The good thing is, you can jump into any part of the project and understand what's going on, feel like it was you who wrote it, because the language is simple and there's only one way of doing things.

Rust's compilation speed is slow, on par with C++. V compiles 1.5 million lines of code per cpu per second.


V vs Rust vs Go: example

Since V's domain is close to both Go and Rust, I decided to use a simple example to compare the three.

It's a simple concurrent program that fetches top Hacker News stories concurrently.

Rust

use serde::Deserialize;
use std::sync::{Arc, Mutex};

const STORIES_URL: &str = "https://hacker-news.firebaseio.com/v0/topstories.json";
const ITEM_URL_BASE: &str = "https://hacker-news.firebaseio.com/v0/item";

#[derive(Deserialize)]
struct Story {
    title: String,
}

fn main() {
    let story_ids: Arc<Vec<u64>> = Arc::new(reqwest::get(STORIES_URL).unwrap().json().unwrap());
    let cursor = Arc::new(Mutex::new(0));
    let mut handles = Vec::new();
    for _ in 0..8 {
        let cursor = cursor.clone();
        let story_ids = story_ids.clone();
        handles.push(std::thread::spawn(move || loop {
            let index = {
                let mut cursor_guard = cursor.lock().unwrap();
                let index = *cursor_guard;
                if index >= story_ids.len() {
                    return;
                }
                *cursor_guard += 1;
                index
            };
            let story_url = format!("{}/{}.json", ITEM_URL_BASE, story_ids[index]);
            let story: Story = reqwest::get(&story_url).unwrap().json().unwrap();
            println!("{}", story.title);
        }));
    }
    for handle in handles {
        handle.join().unwrap();
    }
} 
Go
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"sync"
)

const STORIES_URL = "https://hacker-news.firebaseio.com/v0/topstories.json" 
const ITEM_URL_BASE = "https://hacker-news.firebaseio.com/v0/item" 

type Story struct {
	Title string
}

func main() {
	rsp, err := http.Get(STORIES_URL) 
	if err != nil {
		panic(err)
	}
	defer rsp.Body.Close()
	data, err := ioutil.ReadAll(rsp.Body)
	if err != nil {
		panic(err)
	}
	var ids []int
	if err := json.Unmarshal(data, &ids); err != nil {
		panic(err)
	}
	var cursor int
	var mutex sync.Mutex
	next := func() int {
		mutex.Lock()
		defer mutex.Unlock()
		temp := cursor
		cursor++
		return temp
	}
	wg := sync.WaitGroup{}
	for i := 0; i < 8; i++ {
		wg.Add(1)
		go func() {
			for cursor := next(); cursor < len(ids); cursor = next() {
				url := fmt.Sprintf(
					"%s/%d.json",
                                         ITEM_URL_BASE, 
					ids[cursor],
				)
				rsp, err := http.Get(url)
				if err != nil {
					panic(err)
				}
				defer rsp.Body.Close()

				data, err := ioutil.ReadAll(rsp.Body)
				if err != nil {
					panic(err)
				}
				var story Story
				if err := json.Unmarshal(data, &story); err != nil {
					panic(err)
				}
				fmt.Println(story.Title)
			}
			wg.Done()
		}()
	}
	wg.Wait()
}
V
const STORIES_URL = 'https://hacker-news.firebaseio.com/v0/topstories.json'
const ITEM_URL_BASE = 'https://hacker-news.firebaseio.com/v0/item'

struct Story {
    title string
}

fn main() {
    resp := http.get(STORIES_URL)? 
    ids := json.decode([]int, resp.body)? 
    mut cursor := 0
    for _ in 0..8 {
        go fn() {
            for {
                lock { 
                    if cursor >= ids.len {
                        break
                    }
                    id := ids[cursor]
                    cursor++
                }
                resp := http.get('$ITEM_URL_BASE/$id.json')? 
                story := json.decode(Story, resp.body)?
                println(story.title)
            }
        }()
    }
    runtime.wait() 
}  



Zig

Zig's goals are similar. The things V improves upon:

- Simplicity

- Strings

- No globals

- Easier allocations

- Automatic memory management

- No LLVM dependency

- Hot reloading

- Faster compilation

More languages coming soon...