Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1443 lines (1072 sloc) 32.7 KB
@t header
<script src="/js/jquery.min.js"></script>
<style>
h2 {
border-top: 1px solid #dfdfdf;
padding-top: 10px;
}
str {
color: brown;
font-family: 'Roboto Mono';
}
key {
color: rgb(74,103,154);
font-family: 'Roboto Mono';
}
code {
font-family: 'Roboto Mono';
background-color: #f0f0f0;
padding: 1px 3px 1px 3px;
}
</style>
<script>
$(document).ready(function() {
$('.run').click(function() {
var pre = $(this).prev('pre')
localStorage.setItem('play', pre.text())
window.open('/play')
});
});
</script>
<div class='sep'></div>
<div class='center'>
<div class='toc'>
<a href='#introduction'>Introduction</a>
<a href='#hello'>Hello World</a>
<a href='#comments'>Comments</a>
<a href='#fns'>Functions</a>
<a href='#vars'>Variables</a>
<a href='#btypes'>Basic types</a>
<a href='#strings'>Strings</a>
<a href='#arrays'>Arrays</a>
<a href='#maps'>Maps</a>
<a href='#if'>If</a>
<a href='#for'>For loop</a>
<a href='#switch'>Switch</a>
<a href='#structs'>Structs</a>
<a href='#mod'>Access modifiers</a>
<a href='#methods'>Methods</a>
<a href='#recvs'>Pure functions</a>
<a href='#consts'>Constants</a>
<a href='#modules'>Modules</a>
<a href='#interfaces'>Interfaces</a>
<a href='#enums'>Enums</a>
<a href='#option'>Option types & error handling</a>
<a href='#generics'>Generics</a>
<a href='#concurrency'>Concurrency</a>
<a href='#json'>Decoding JSON</a>
<a href='#testing'>Testing</a>
<a href='#memory'>Memory management</a>
<br>
Advanced Topics
<br>
<br>
<a href='#calling_c'>Calling C functions from V</a>
<a href='#comp_if'>Compile time if</a>
<a href='#codegen'>Reflection via codegen</a>
<a href='#op'>Limited operator overloading</a>
<a href='#cpp'>Translating C/C++ to V</a>
<a href='#hot'>Hot code reloading</a>
<a href='#cross'>Cross compilation</a>
<br>
<a href='#keywords'>Appendix I: Keywords</a>
</div>
<div class='docs'>
<h2 id=introduction style='border:0; margin-top:0; padding-top:20px;'>Introduction</h2>
V is a statically typed compiled programming language designed for building maintainable software.
<p>
It's similar to Go and is also influenced by Oberon, Rust, Swift.
<p>
V is a very simple language. Going through this documentation will take you about half an hour,
and by the end of it you will learn pretty much the entire language.
<p>
Despite being simple, it gives a lot of power to the developer. Anything you can do in other languages,
you can do in V.
<!--
<p>
V is very strict. It helps with safety, readability, and maintainability.
-->
<p>
Found an error/typo? Please <a target=_blank
href='https://github.com/vlang-io/website/blob/master/docs.html'>submit a pull request</a>.
<h2 id=hello>Hello World</h2>
<pre><key>fn</key> main() {
println(<str>'hello world'</str>)
}</pre>
<input class='run' type='button' value='Run'>
<p>
Functions are declared with <code>fn</code>. Return type goes after the function
name. In this case <code>main</code> doesn't return anything, so the type is
omitted.
<p>
Just like in C and all related languages, <code>main</code> is an entry point.
<p>
<code>println</code> is one of the few built-in functions. It prints the value
to standard output.
<p><code>fn main()</code> declaration can be skipped in one file programs.
This is useful when writing small programs, "scripts", or just learning
the language. For brevity, <code>fn main()</code> will be skipped in this
tutorial.
<p>
This means that a "hello world" program can be as simple as
<pre>
println(<str>'hello world'</str>)
</pre>
<input class='run' type='button' value='Run'>
<h2 id=comments>Comments</h2>
<pre>
<comment>// This is a single line comment.
/* This is a multiline comment.
/* It can be nested. */
*/</comment></pre>
<h2 id=fns>Functions</h2>
<pre>
<key>fn </key>main() {
println(add(77, 33))
println(sub(100, 50))
}
<key>fn </key>add(x int, y int) int {
return x + y
}
<key>fn </key>sub(x, y int) int {
return x - y
}
</pre>
<input class='run' type='button' value='Run'>
<p>
Again, the type comes after the argument's name.<!-- If two or more arguments in a row have the same type,
shorter notation can be used: <code>a</code>
can be listed
-->
<p>
Just like in Go and C, functions cannot be overloaded. This simplifies the code and improves
maintainability and readability.
<p>
Functions can be used before their declaration:
<code>add</code> and <code>sub</code> are declared after <code>main</code>, but
can still be called from <code>main</code>.
<!--
unlike C, Python, F#
-->
This is true for all declarations in V and eliminates the need of header files
or thinking about the order of files and declarations.
<h2 id=vars>Variables</h2>
<pre>
name := <str>'Bob'</str>
age := 20
large_number := i64(9999999999)
println(name)
println(age)
println(large_number)
</pre>
<input class='run' type='button' value='Run'>
<p>
Variables are declared and initialized with <code>:=</code>. This is the only
way to declare variables in V. This means that variables always have an initial
value.
<p>
The variable's type is inferred from the value on the right hand side.
To force a different type, use type conversion:
the expression <code>T(v)</code> converts the value <code>v</code> to the
type <code>T</code>.
<p>
Unlike most other languages, V only allows defining variables in functions.
Global (module level) variables are not allowed. There's no global state in V.
<!--You can read why <a href='#'> here</a>.-->
<p>&nbsp;</p>
<pre>
<key>mut</key> age := 20
println(age)
age = 21
println(age)
</pre>
<input class='run' type='button' value='Run'>
<p>
To change the value of the variable use <code>=</code>. In V, variables are
immutable by default. To be able to change the value of the variable, you
have to declare it with <code>mut</code>.
<p>Try compiling the program above after removing <code>mut</code> from
the first line.
<p>
Please note the difference between <code>:=</code> and <code>=</code><br> <code>:=</code>
is used for declaring and initializing, <code>=</code> is used for assigning.
<p>&nbsp;</p>
<pre>
<key>fn </key>main() {
age = 21
}
</pre>
<input class='run' type='button' value='Run'>
<p>
This code will not compile, because variable <code>age</code> is not declared.
All variables need to be declared in V.
<p>&nbsp;</p>
<pre>
<key>fn </key>main() {
age := 21
}
</pre>
<input class='run' type='button' value='Run'>
<p>
This code will not compile either, because unused variables result in a compilation error.
<p>&nbsp;</p>
<pre>
<key>fn </key>main() {
a := 10
if true {
a := 20
}
}
</pre>
<input class='run' type='button' value='Run'>
<p>
Unlike most languages, variable shadowing is not allowed. Declaring a variable with a name that is already
used in a parent scope will result in a compilation error.
<h2 id=btypes>Basic types</h2>
<pre>
bool
string
i8 i16 i32 i64
u8 u16 u32 u64
byte <comment>// alias for u8 </comment>
int <comment>// alias for i32 </comment>
rune <comment>// alias for i32, represents a Unicode code point </comment>
f32 f64
</pre>
Please note that unlike C and Go, <code>int</code> is always a 32 bit integer.
<h2 id=strings>Strings</h2>
<pre>
name := <str>'Bob'</str>
println(<str>'Hello, </str>$name<str>!'</str>) <comment>// `$` is used for string interpolation</comment>
println(name.len)
bobby := name + <str>'by'</str> <comment>// + is used to concatenate strings</comment>
println(bobby) <comment>// ==> "Bobby" </comment>
println(bobby.substr(1, 3)) <comment>// ==> "ob" </comment>
<comment>// println(bobby[1:3]) // This syntax will most likely replace the substr() method </comment>
</pre>
<input class='run' type='button' value='Run'>
<p>
In V, a string is a read-only array of bytes. String data is encoded using UTF-8.
<p>
Both single and double quotes can be used to denote strings (TODO: double quotes are not supported
yet). For consistency, <code>vfmt</code> converts double quotes to single quotes unless the string
contains a single quote character.
<p>
Strings are immutable. This means that the substring function is very efficient:
no copying is performed, no extra allocations required.
<p>
&nbsp;
<p>
All operators in V must have values of the same type on both sides.
This code will not compile if <code>age</code> is an <code>int</code>:
<pre>println(<str>'age = '</str> + age)</pre>
We have to either convert <code>age</code> to a <code>string</code>:
<pre>println(<str>'age = '</str> + age.str())</pre> or use string interpolation (preferred):
<pre>println(<str>'age = $age'</str>)</pre>
<!--
or simply pass a second argument to <code>println</code>:
<pre>println(<str>'age = '</str>, age) <comment>// TODO: not implemented yet</comment></pre>
-->
<h2 id=arrays>Arrays</h2>
<pre>
nums := [1, 2, 3]
println(nums)
println(nums[1]) <comment>// ==> "2"</comment>
<key>mut</key> names := [<str>'John'</str>]
names << <str>'Peter'</str>
names << <str>'Sam'</str>
<comment>// names << 10 <-- This will not compile. `names` is an array of strings.</comment>
println(names.len) <comment>// ==> "3"</comment>
println(<str>'Alex'</str> <key>in</key> names) <comment>// ==> "false"</comment>
<comment>// We can also preallocate a certain amount of elements.</comment>
nr_ids := 50
mut ids := [0 ; nr_ids] <comment>// This creates an array with 50 zeroes</comment>
<!--
for i := 0; i < nr_ids; i++ {
ids[i] = i <comment>// This is more efficient than </comment>
<comment>// ids << i</comment>
}
-->
</pre>
<input class='run' type='button' value='Run'>
<p>
Array type is determined by the first element: <code>[1, 2, 3]</code> is an array of ints <br>
(<code>[]int</code>). <br>
<code>['a', 'b']</code> is an array of strings (<code>[]string</code>).
<p>
All elements must have the same type. <code>[1, 'a']</code> will not compile.
<p>
<code>&lt;&lt;</code> is an operator that appends a value to the end of the array.
<p><code>.len</code> field returns the length of the array. Note, that it's a read-only field,
and it can't be modified by the user. All exported fields are read-only by default in V.
<p><code>val in array</code> returns true if the array contains <code>val</code>.
<h2 id=maps>Maps</h2>
<pre>
<key>mut</key> m := map[string]int{} <comment>// Only maps with string keys are allowed for now </comment>
m[<str>'one'</str>] = 1
println(m[<str>'one'</str>]) <comment>// ==> "1" </comment>
println(m[<str>'bad_key'</str>]) <comment>// ==> "0" </comment>
<comment>// TODO: implement a way to check if the key exists</comment>
numbers := { <comment>// TODO: this syntax is not implemented yet </comment>
<str>'one'</str>: 1,
<str>'two'</str>: 2,
}
</pre>
<h2 id=if>If</h2>
<pre>
a := 10
b := 20
<key>if </key>a < b {
println(<str>'$a < $b'</str>)
} <key>else if </key>a > b {
println(<str>'$a > $b'</str>)
} <key>else</key> {
println(<str>'$a == $b'</str>)
}
</pre>
<input class='run' type='button' value='Run'>
<p>
<code>if</code> statements are pretty straightforward and similar to most
other languages.
<p>
Unlike other C-like languages, there are no parentheses surrounding the
condition, and the braces are always required.
</p>
<p>
<code>if</code> can be used as an expression:
<pre>
num := 777
s := <key>if</key> num % 2 == 0 {
<str>'even'</str>
}
<key>else</key> {
<str>'odd'</str>
}
println(s) <comment>// ==> "odd"</comment>
</pre>
<h2 id=for>For loop</h2>
V has only one looping construct: <code>for</code>.
<pre>
numbers := [1, 2, 3, 4, 5]
<key>for</key> num <key>in</key> numbers {
println(num)
}
names := [<str>'Sam'</str>, <str>'Peter'</str>]
<key>for</key> i, name <key>in</key> names {
println(<str>'$i) $name'</str>) // Output: 0) Sam
} // 1) Peter
</pre>
<input class='run' type='button' value='Run'>
<p>
The <code>for .. in</code> loop is used for going through elements of an array.
If an index is required, an alternative form <code>for index, value in</code> can be used.
<p>&nbsp;</p>
<pre>
mut sum := 0
mut i := 0
for i <= 100 {
sum += i
i++
}
println(sum) // ==> "5050"
</pre>
<input class='run' type='button' value='Run'>
<p>
This form of the loop is similar to <code>while</code>
loops in other languages.
<p>
The loop will stop iterating once the boolean condition evaluates to false.
<p>
Again, there are no parentheses surrounding the
condition, and the braces are always required.
<p>&nbsp;</p>
<pre>
mut num := 0
for {
num++
<key>if </key>num >= 10 {
break
}
}
println(num) // ==> "10"
</pre>
<input class='run' type='button' value='Run'>
<p>
The condition can be omitted, this results in an infinite loop.
<p>&nbsp;</p>
<pre>
for i := 0; i < 10; i++ {
println(i)
}
</pre>
<input class='run' type='button' value='Run'>
<p>
Finally, there's the traditional C style <code>for</code> loop. It's safer than the `while` form
because with the latter it's easy to forget to update the counter and get
stuck in an infinite loop.
<p>
Here <code>i</code> doesn't need to be declared with <code>mut</code> since it's always going to be mutable by definition.
<h2 id=switch>Switch</h2>
<pre>
os := 'windows'
print('V is running on ')
switch os {
case 'darwin':
println('macOS.')
case 'linux':
println('Linux.')
default:
println(os)
}
<comment>// TODO: replace with match expressions</comment>
</pre>
<input class='run' type='button' value='Run'>
<p>
A switch statement is a shorter way to write a sequence of <code>if - else</code> statements. It runs the first case whose value is equal to the condition expression.
<p>
Unlike C, <code>break</code> statement is not needed at the end of every block.
<h2 id=structs>Structs</h2>
<pre>
<key>struct</key> Point {
x int
y int
}
p := Point{
x: 10
y: 20
}
println(p.x) <comment>// Struct fields are accessed using a dot</comment>
</pre>
<input class='run' type='button' value='Run'>
<p> &nbsp;
<p>
Structs are allocated on the stack. To allocate a struct on the heap and get
a pointer to it, use the <code>&</code> prefix:
<pre>
pointer := &Point{10, 10} <comment>// Alternative initialization syntax for structs with 3 fields or fewer</comment>
println(pointer.x) <comment>// Pointers have the same syntax for accessing fields </comment>
</pre>
<p> &nbsp;
<p>
V doesn't have subclassing, but it supports embedded structs:
<pre>
<comment>// TODO: this will be implemented later in June</comment>
<key>struct</key> Button {
Widget
title string
}
button := new_button(<str>'Click me'</str>)
button.set_pos(x, y)
<comment>// Without embedding we'd have to do</comment>
button.widget.set_pos(x,y)
</pre>
<h2 id=mod>Access modifiers</h2>
<p>
Struct fields are private and immutable by default (making structs immutable as well).
Their access modifiers can be changed with
<code>pub</code> and <code>mut</code>. In total, there are 5 possible options:
<pre><key>struct</key> Foo {
a int <comment>// private immutable (default)</comment>
<key>mut</key>:
b int <comment>// private mutable</comment>
c int <comment>// (you can list multiple fields with the same access modifier) </comment>
<key>pub</key>:
d int <comment>// public immmutable (readonly)</comment>
<key>pub mut</key>:
e int <comment>// public, but mutable only in parent module </comment>
<key>pub mut mut</key>:
f int <comment>// public and mutable both inside and outside parent module </comment>
} <comment>// (not recommended to use, that's why it's so verbose)</comment>
</pre>
<p> &nbsp;
<p>
For example, here's the <code>string</code> type defined in the <code>builtin</code> module:
<pre>
<key>struct</key> string {
str byteptr
<key>pub</key>:
len int
}
</pre>
<p>
It's easy to see from this definition that
<code>string</code> is an immutable type.
<p>
The byte pointer with the string data is not accessible outside <code>builtin</code> at all.
<code>len</code> field is public, but not mutable.
<pre>
<key>fn</key> main() {
str := <str>'hello'</str>
len := str.len <comment>// OK </comment>
str.len++ <comment>// Compilation error </comment>
}
</pre>
<h2 id=methods>Methods</h2>
<!--
<pre>
import math
struct Point {
x int
y int
}
<key>fn </key>(a Point) distance_to(b Point) f64 {
return math.sqrt((a.x-b.x)**2 + (a.y-b.y)**2)
}
p := Point{10,10}
p2 := Point{20,20}
println(p.distance_to(p2))
</pre>
-->
<pre>
struct User {
age int
}
<key>fn </key>(u User) can_register() bool {
return u.age > 16
}
user := User{age: 10}
println(user.can_register()) <comment>// ==> "false" </comment>
user2 := User{age: 20}
println(user2.can_register()) <comment>// ==> "true" </comment>
</pre>
<input class='run' type='button' value='Run'>
<p>
V doesn't have classes. But you can define methods on types.
<p>
A method is a function with a special receiver argument.
<p>
The receiver appears in its own argument list between the <code>fn</code> keyword and the method name.
<p>
<!--
In this example, the <code>distance_to</code> method has a receiver of type <code>Point</code>
named <code>a</code>.
-->
In this example, the <code>can_register</code> method has a receiver of type <code>User</code>
named <code>u</code>. The convention is not to use receiver names like <code>self</code> or
<code>this</code>, but a short, preferably one letter long, name.
<h2 id=recvs>Pure functions by default</h2>
V functions are pure by default, meaning that their return values are only determined by
their arguments, and their evaluation has no side effects.
<p>
This is achieved by lack of global variables and all function arguments being
immutable by default, even when references are passed.
<p>
V is not a pure functional language however. It is possible to modify function arguments
by using the same keyword <code>mut</code>:
<pre><key>struct</key> User {
is_registered bool
}
<key>fn </key>(u <key>mut</key> User) register() {
u.is_registered = true
}
mut user := User{}
println(user.is_registered) <comment>// ==> "false" </comment>
user.register()
println(user.is_registered) <comment>// ==> "true" </comment>
</pre>
<input class='run' type='button' value='Run'>
<p>
In this example, the receiver (which is simply the first argument) is marked as mutable,
so <code>register()</code> can change the user object.
The same works with non-receiver arguments:
<pre>
<key>fn</key> multiply_by_2(arr <key>mut</key> []int) {
<key>for</key> i := 0; i < arr.len; i++ {
arr[i] *= 2
}
}
<key>mut</key> nums := [1, 2, 3]
multiply_by_2(<key>mut</key> nums)
println(nums) <comment>// ==> "[2, 4, 6]"
</pre>
<p>
Note, that you have to add <code>mut</code> before <code>nums</code> when calling this function. This makes
it clear that the function being called will modify the value.
<!--
<p>
Please note that functions can only modify receivers.<br><code><key>fn </key>register(u mut User)</code>
will not compile.
<p>
This is very important, so I'll say it again: V functions are partially pure, their arguments can
never be modified by the function.
<p>
-->
<p>It is preferable to return values instead of modifying arguments.
Modifying arguments should only be done in performance-critical parts of your application
to reduce allocations and copying.
<p>
Use <code>user.register()</code> or <code>user = register(user)</code>
instead of <code>register(mut user)</code>.
<p>
V makes it easy to return a modifed version of an an object: <br>
<pre>
<key>fn </key>register(u User) User {
return { u | is_registered: true }
}
user = register(user)
</pre>
<h2 id=consts>Constants</h2>
<pre>
<key>const</key> (
PI = 3.14
World = <str>'世界'</str>
)
println(PI)
println(World)
</pre>
<input class='run' type='button' value='Run'>
<p>
Constants are declared with <code>const</code>. They can only be defined
at the module level (outside of functions).
<p>
Constant names must be capitalized. This helps distinguish them from variables.
<p>
Constant values can never be changed.
<p>
V constants are more flexible than in most languages. You can assign more complex values:
<pre>
<key>struct</key> Color {
r int
g int
b int
}
<key>fn </key>(c Color) str() string { return <str>'{$c.r, $c.g, $c.b}'</str> }
<key>fn </key>rgb(r, g, b int) Color { return Color{r: r, g: g, b: b} }
<key>const</key> (
Numbers = [1, 2, 3]
Red = Color{r: 255, g: 0, b: 0}
Blue = rgb(0, 0, 255)
)
println(Numbers)
println(Red)
println(Blue)
</pre>
<input class='run' type='button' value='Run'>
<p>
Global variables are not allowed, so this can be really useful.
<h2 id=modules>Modules</h2>
V is a very modular language. Creating reusable modules is encouraged and is
very simple.
To create a new module, create a directory with your module's name and
.v files with code:
<pre>
cd ~/code/modules
mkdir mymodule
vim mymodule/mymodule.v
<comment>// mymodule.v</comment>
<key>module</key> mymodule
<comment>// To export a function we have to use `pub`</comment>
<key>pub fn</key> say_hi() {
println(<str>'hello from mymodule!'</str>)
}
</pre>
You can have as many .v files in <code>mymodule/</code> as you want.
<p>
Build it with <code>v -lib ~/code/modules/mymodule</code>.
<p>
That's it, you can now use it in your code:
<pre>
<key>module</key> main
<key>import</key> mymodule
<key>fn </key>main() {
mymodule.say_hi()
}
</pre>
<p>
Note that you have to specify the module every time you call an external function.
This may seem verbose at first, but it makes code much more readable
and easier to understand, since it's always clear which function from
which module is being called. Especially in large code bases.
<p>
Module names should be short, under 10 characters. Circular imports are not allowed.
<p>
You can create modules anywhere.
<p>
All modules are compiled statically into a single executable.
<h2 id=interfaces>Interfaces</h2>
<pre>
<key>struct</key> Dog {}
<key>struct</key> Cat {}
<key>fn </key>(d Dog) speak() string {
return <str>'woof'</str>
}
<key>fn </key>(c Cat) speak() string {
return <str>'meow' </str>
}
<key>interface</key> Speaker {
speak() string
}
<key>fn </key>perform(s Speaker) {
println(s.speak())
}
dog := Dog{}
cat := Cat{}
perform(dog) <comment>// ==> "woof" </comment>
perform(cat) <comment>// ==> "meow" </comment>
</pre>
<input class='run' type='button' value='Run'>
<p>
A type implements an interface by implementing its methods. There is no explicit declaration of intent, no "implements" keyword.
</p>
<!--
<p>
V interfaces are very efficient. There's no dynamic dispatch.
</p>
-->
<h2 id=enums>Enums</h2>
<!--
<pre>
enum Color {
red, green, blue
}
mut color := Color.red
println(color) // ==> "red"
color = .green
is_green := color == .green
</pre>
-->
<pre>
<key>enum</key> Color {
red green blue
}
mut color := Color.red
<comment>// V knows that color is a Color. No need to use `Color.green` here.</comment>
color = .green
println(color) <comment>// ==> "1" TODO: print "green"? </comment>
</pre>
<input class='run' type='button' value='Run'>
<h2 id=option>Option/Result types & error handling</h2>
<pre><key>struct</key> User {
id int
}
<key>struct</key> Repo {
users []User
}
<key>fn </key>new_repo() Repo {
user := User{id:10}
return Repo {
users: [user]
}
}
<key>fn </key>(r Repo) find_user_by_id(id int) User? {
for user in r.users {
<key>if </key>user.id == id {
<comment>// V automatically wraps this into an option type </comment>
return user
}
}
return error(<str>'User </str>$id<str> not found'</str>)
}
repo := new_repo()
user := repo.find_user_by_id(10) or { <comment>// Option types must be handled by `or` blocks </comment>
return // <comment>`or` block must end with `return`, `break`, or `continue` </comment>
}
println(user.id) // <comment>==> "10" </comment>
</pre>
<!--
eprintln(err)
-->
<input class='run' type='button' value='Run'>
<p>V combines Option and Result into one type, so you don't need to decide which one to use.
<p>
The amount of work required to "upgrade" a function to an optional function is minimal:
you have to add a <code>?</code> to the return type and return an error when something goes wrong.
<p>
If you don't need to return an error, you can simply <code>return None</code>. (TODO: <code>None</code> is
not implemented yet).
<p>
This is the primary way of handling errors in V. They are still values, like in Go,
but the advantage is that errors can't be unhandled, and handling them is a lot less verbose.
<p>
You can also propagate errors:
<pre>
resp := http.get(url)?
println(resp.body)
</pre>
<code>http.get</code> returns <code>?http.Response</code>. It was called with
<code>?</code>, so the error is propagated to the calling function or in case of
<code>main</code> leads to a panic.
<p>Basically the code above is a shorter version of
<pre>
resp := http.get(url) or {
panic(err)
}
println(resp.body)
</pre>
<h2 id=generics>Generics (July)</h2>
<pre><key>struct</key> Repo&lt;T> {
db DB
}
<key>fn </key>new_repo&lt;T>(db DB) Repo&lt;T> {
return Repo&lt;T>{db: db}
}
<comment>// This is a generic function. V will generate it for every type it's used with.</comment>
<key>fn </key>(r Repo&lt;T>) find_by_id(id int) ?T {
table_name := T.name <comment>// in this example getting the name of the type gives us the table name</comment>
return r.db.query_one&lt;T>('select * from $table_name where id = ?', id)
}
db := new_db()
users_repo := new_repo&lt;User>(db)
posts_repo := new_repo&lt;Post>(db)
user := users_repo.find_by_id(1)?
post := posts_repo.find_by_id(1)?
</pre>
<h2 id=concurrency>Concurrency</h2>
The concurrency model is very similar to Go. To run <code>foo()</code> concurrently, just
call it with <code>go foo()</code>. Right now, it launches the function in a new system
thread. Soon goroutines and the scheduler will be implemented.
<h2 id=json>Decoding JSON</h2>
<pre><key>struct</key> User {
name string
age int
foo Foo [skip] <comment>// Use `skip` attribute to skip certain fields</comment>
}
data := <str>'{ "name": "Frodo", "age": 25 }'</str>
user := json.decode(User, data) <key>or</key> {
eprintln(<str>'Failed to decode json'</str>)
return
}
println(user.name)
println(user.age)
</pre>
<input class='run' type='button' value='Run'>
<p>
JSON is very popular nowadays, that's why JSON support is built in.
<p>
The first argument of the <code>json.decode</code> function is the type to decode to.
The second argument is the JSON string.
<p>
V generates code for JSON encoding and decoding. No runtime reflection is used. This results in much better
performance.
<h2 id=testing>Testing</h2>
<pre><comment>// hello.v</comment>
<key>fn </key>hello() string {
return <str>'Hello world'</str>
}
<comment>// hello_test.v</comment>
<key>fn </key>test_hello() {
<key>assert</key> hello() == <str>'Hello world'</str>
}
</pre>
All test functions have to be placed in <code>*_test.v</code> files and begin with <code>test_</code>.
To run the tests do <code>v hello_test.v</code>. To test an entire module, do
<code>v test mymodule</code>.
<h2 id=memory>Memory management</h2>
There's no garbage collection or reference counting. V cleans up what it can
during compilation. For example:
<pre>
<key>fn</key> draw_text(s string, x, y int) {
...
}
<key>fn</key> draw_scene() {
...
draw_text(<str>'hello $name1'</str>, 10, 10)
draw_text(<str>'hello $name2'</str>, 100, 10)
draw_text(strings.repeat(<str>'X'</str>, 10000), 10, 50)
...
}
</pre>
The strings don't escape <code>draw_text</code>, so they are cleaned up when
the function exits.
<p>
In fact, the first two calls won't result in any allocations at all.
These two strings are small,
V will use a preallocated buffer for them.
<p>
For more complex cases manual memory management is required. This will be
fixed soon.
<p>V will detect memory leaks at runtime and report them. To clean up, for example,
an array, use the <code>free()</code> method:
<pre>
numbers := [0; 1000000]
...
numbers.free()
</pre>
<h1>Advanced Topics</h1>
<h2 id=calling_c>Calling C functions from V</h2>
<pre>
#flag -lsqlite3
#include "sqlite3.h"
struct C.sqlite3
struct C.sqlite3_stmt
<key>fn </key>C.sqlite3_column_int(C.sqlite_stmt, int) int
<key>fn </key>main() {
path := 'sqlite3_users.db'
db := &C.sqlite3{}
C.sqlite3_open(path.cstr(), &db)
query := 'select count(*) from users'
stmt := &C.sqlite3_stmt{}
C.sqlite3_prepare_v2(db, query.cstr(), - 1, &stmt, 0)
C.sqlite3_step(stmt)
nr_users := C.sqlite3_column_int(res, 0)
C.sqlite3_finalize(res)
println(nr_users)
}
</pre>
<h2 id=comp_if>Compile time if</h2>
<pre><key>$if</key> windows {
println('Windows')
}
<key>$if</key> linux {
println('Linux')
}
<key>$if</key> mac {
println('macOS')
}
</pre>
Compile time <code>if</code> starts with a <code>$</code>. Right now it can only be used to detect
an OS.
<h2 id=codegen>Reflection via codegen</h2>
Having built-in JSON support is nice, but V also allows you to create efficient
serializers for anything, using compile-time <key>if</key> and <key>for</key>:
<pre>
<pre><key>struct</key> User {
name string
age int
}
<comment>// TODO: planned in June</comment>
<key>fn</key> decode&lt;T>(data string) T {
mut result := T{}
$for field in T.fields {
$if field is string {
result.$field = get_string(data, field.name)
} else $if field is int {
result.$field = get_int(data, field.name)
}
}
return result
}
<comment>// decode&lt;User> generates:</comment>
<key>fn</key> decode_User(data string) User {
mut result := User{}
result.name = get_string(data, 'name')
result.age = get_int(data, 'age')
return result
}
</pre>
<h2 id=op> Limited operator overloading</h2>
<pre><key>struct</key> Vec {
x int
y int
}
<key>fn</key> (a Vec) str() string {
<key>return</key> <str>'{$a.x, $a.y}'</str>
}
<key>fn</key> (a Vec) + (b Vec) Vec {
<key>return</key> Vec {
a.x + b.x,
a.y + b.y
}
}
<key>fn</key> (a Vec) - (b Vec) Vec {
<key>return</key> Vec {
a.x - b.x,
a.y - b.y
}
}
<key>fn</key> main() {
a := Vec{2, 3}
b := Vec{4, 5}
println(a + b) <comment>// ==> "{6, 8}" </comment>
println(a - b) <comment>// ==> "{-2, -2}" </comment>
}
</pre>
<input class='run' type='button' value='Run'>
<p>
Operator overloading goes against V's philosophy of simplicity and predictability. But since
scientific and graphical applications are among V's domains, operator overloading is very important to have
in order to improve readability:
<p>
<code>a.add(b).add(c.mul(d))</code> is a lot less readable than <code>a + b + c * d</code>.
<p>
To improve safety and maintainability, operator overloading has several limitations:
<p>
- It's only possible to overload <code>+, -, *, /</code> operators. <br>
- Calling other functions inside operator functions is not allowed. <br>
- Operator functions can't modify their arguments. <br>
- Both arguments must have the same type (just like with all operators in V).
<h2 id=cpp>Translating C/C++ to V</h2>
TODO: translating C to V will be available in June. C++ to V will be available later this year.
<p>
V can translate your C/C++ code to human readable V code.
Let's create a simple program <code>test.cpp</code> first:
<pre>#include &lt;vector>
#include &lt;string>
#include &lt;iostream>
int main() {
std::vector&lt;std::string> s;
s.push_back("V is ");
s.push_back("awesome");
std::cout << s.size() << std::endl;
return 0;
}
</pre>
Run <code>v translate test.cpp</code> and V will generate <code>test.v</code>:
<pre><key>fn </key>main {
mut s := []
s << 'V is '
s << 'awesome'
println(s.len)
}
</pre>
<p>
An online C/C++ to V translator is coming soon.
<p>
When should you translate C code and when should you simply call C code from V?
<p>
If you have well-written, well-tested C code, then of course you can always simply call this C code from V.
<p>
Translating it to V gives you several advantages:
<p>
- If you plan to develop that code base, you now have everything in one language, which is much safer and easier to develop in that C.
<p>
- Cross-compilation becomes a lot easier. You don't have to worry about it at all.
<p>
- No more build flags and include files either.
<h2 id=hot>Hot code reloading</h2>
TODO
<h2 id=cross>Cross compilation</h2>
To cross compile your project simply run
<pre>
v -os windows .
</pre>
or
<pre>
v -os linux .
</pre>
(Cross compiling for macOS is temporarily not possible.)
<p>
If you don't have any C dependencies, that's all you need to do. This works even
when compiling GUI apps using the <code>ui</code> module or graphical apps using
<code>gg</code>.
<h2 id=keywords>Appendix I: Keywords</h2>
V has 22 keywords:
<pre>
break
const
continue
defer
else
enum
fn
for
go
goto
if
import
in
interface
is
match
module
mut
or
return
struct
type
</pre>
</div>
</div>
</body>
</html>
@t footer
You can’t perform that action at this time.