module main // main module import os { input, user_os } import time import math type MyTime = time.Time fn main() { println('hello world') println(sub(100, 50)) n := write_log(.return_error) or { println('Error: $err') 0 } println('$n bytes written') // Functions can be passed to other functions println(run(5, sqr)) // "25" // Anonymous functions can be declared inside other functions: double_fn := fn (n int) int { return n + n } println(run(5, double_fn)) // "10" // Functions can be passed around without assigning them to variables: res := run(5, fn (n int) int { return n + n }) println(res) // "10" // You can even have an array/map of functions: fns := [sqr, cube] println(fns[0](10)) // "100" fns_map := { 'sqr': sqr 'cube': cube } println(fns_map['cube'](2)) // "8" } fn add(x int, y int) int { return x + y } fn sub(x int, y int) int { return x - y } // This is a single line comment. /* This is a multiline comment. /* It can be nested. */ */ fn foo() (int, int) { return 2, 3 } a, b := foo() println(a) // 2 println(b) // 3 c, _ := foo() // ignore values using `_` name := 'Bob' assert name.len == 3 s := r'hello\nworld' // all int literals are supported assert '0xc3'.int() == 195 assert '0o10'.int() == 8 assert '0b1111_0000_1010'.int() == 3850 assert '-0b1111_0000_1010'.int() == -3850 name := 'Bob' println('Hello, $name!') // Hello, Bob! x := 123.4567 println('[${x:.2}]') println('[${x:10}]') println('[${int(x):-10}]') println('[${int(x):010}]') println('[${int(x):b}]') println('[${int(x):o}]') println('[${int(x):X}]') println('[${10.0000:.2}]') println('[${10.0000:.2f}]') rocket := `π` assert rocket.bytes() == [u8(0xf0), 0x9f, 0x9a, 0x80] assert `\x61` == `a` assert `\141` == `a` assert `\u0061` == `a` // multibyte literals work too assert `\u2605` == `β ` assert `\u2605`.bytes() == [u8(0xe2), 0x98, 0x85] assert `\xe2\x98\x85`.bytes() == [u8(0xe2), 0x98, 0x85] assert `\342\230\205`.bytes() == [u8(0xe2), 0x98, 0x85] a := 0x7B b := 0b01111011 c := 0o173 num := 1_000_000 three := 0b0_11 float_num := 3_122.55 hexa := 0xF_F oct := 0o17_3 a := i64(123) b := u8(42) c := i16(12345) f := 1.0 f1 := f64(3.14) f2 := f32(3.14) f0 := 42e1 // 420 f1 := 123e-2 // 1.23 f2 := 456e+2 // 45600 mut nums := [1, 2, 3] nums << 4 println(nums) nums << [5, 6, 7] mut names := ['John'] names << 'Peter' names << 'Sam' names := ['John', 'Peter', 'Sam'] println('Alex' in names) // "false" mut nums := [1, 2, 3] println(nums.len) // "3" println(nums.cap) // "3" or greater nums = [] // The array is now empty println(nums.len) // "0" mut a := []int{len: 10000, cap: 30000, init: 3} users := []int{} mut numbers := []int{cap: 1000} println(numbers.len) // 0 // Now appending elements won't reallocate for i in 0 .. 1000 { numbers << i } mut square := []int{len: 6, init: it * it} // square == [0, 1, 4, 9, 16, 25] struct Point { x int y int } struct Line { p1 Point p2 Point } type ObjectSumType = Line | Point mut object_list := []ObjectSumType{} object_list << Point{1, 1} object_list << Line{ p1: Point{3, 3} p2: Point{4, 4} } dump(object_list) /* object_list: [ObjectSumType(Point{ x: 1 y: 1 }), ObjectSumType(Line{ p1: Point{ x: 3 y: 3 } p2: Point{ x: 4 y: 4 } })] */ mut a := [][]int{len: 2, init: []int{len: 3}} a[0][1] = 2 nums := [1, 2, 3, 4, 5, 6] even := nums.filter(it % 2 == 0) println(even) // [2, 4, 6] // filter can accept anonymous functions even_fn := nums.filter(fn (x int) bool { return x % 2 == 0 }) println(even_fn) nums := [1, 2, 3] println(nums.any(it == 2)) // true println(nums.all(it >= 2)) // false mut numbers := [1, 3, 2] numbers.sort() // 1, 2, 3 numbers.sort(a > b) // 3, 2, 1 struct User { age int name string } mut users := [User{21, 'Bob'}, User{20, 'Zarkon'}, User{25, 'Alice'}] users.sort(a.age < b.age) // sort by User.age int field users.sort(a.name > b.name) // reverse sort by User.name string field custom_sort_fn := fn (a &User, b &User) int { // return -1 when a comes before b // return 0, when both are in same order // return 1 when b comes before a if a.name == b.name { if a.age < b.age { return 1 } if a.age > b.age { return -1 } return 0 } if a.name < b.name { return -1 } else if a.name > b.name { return 1 } return 0 } users.sort_with_compare(custom_sort_fn) nums := [0, 10, 20, 30, 40] println(nums[1..4]) // [10, 20, 30] println(nums[..4]) // [0, 10, 20, 30] println(nums[1..]) // [10, 20, 30, 40] mut a := [0, 1, 2, 3, 4, 5] mut b := a[2..4].clone() a := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] println(a#[-3..]) // [7, 8, 9] println(a#[-20..]) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] println(a#[-20..-8]) // [0, 1] println(a#[..-3]) // [0, 1, 2, 3, 4, 5, 6] // empty arrays println(a#[-20..-10]) // [] println(a#[20..10]) // [] println(a#[20..30]) // [] files := ['pippo.jpg', '01.bmp', '_v.txt', 'img_02.jpg', 'img_01.JPG'] filtered := files.filter(it#[-4..].to_lower() == '.jpg').map(it.to_upper()) mut fnums := [3]int{} // fnums is a fixed size array with 3 elements. fnums[0] = 1 fnums[1] = 10 fnums[2] = 100 println(fnums) // => [1, 10, 100] println(typeof(fnums).name) // => [3]int anums := fnums[..] mut m := map[string]int{} // a map with `string` keys and `int` values m['one'] = 1 m['two'] = 2 println(m['one']) // "1" println(m['bad_key']) // "0" println('bad_key' in m) // Use `in` to detect whether such key exists println(m.keys()) // ['one', 'two'] m.delete('two') numbers := { 'one': 1 'two': 2 } println(numbers) arr := [1, 2, 3] large_index := 999 val := arr[large_index] or { panic('out of bounds') } println(val) // you can also do this, if you want to *propagate* the access error: val2 := arr[333]? println(val2) name := os.input('Enter your name: ') println('Hello, $name!') fn (mut t MyTime) century() int { return int(1.0 + math.trunc(f64(t.year) * 0.009999794661191)) } fn main() { mut my_time := MyTime{ year: 2020 month: 12 day: 25 } println(time.new_time(my_time).utc_string()) println('Century: $my_time.century()') } a := 10 b := 20 if a < b { println('$a < $b') } else if a > b { println('$a > $b') } else { println('$a == $b') } num := 777 s := if num % 2 == 0 { 'even' } else { 'odd' } println(s) // "odd" struct Abc { val string } struct Xyz { foo string } type Alphabet = Abc | Xyz x := Alphabet(Abc{'test'}) // sum type if x is Abc { // x is automatically casted to Abc and can be used here println(x) } if x !is Abc { println('Not Abc') } match x { Abc { // x is automatically casted to Abc and can be used here println(x) } Xyz { // x is automatically casted to Xyz and can be used here println(x) } } nums := [1, 2, 3] println(1 in nums) // true println(4 !in nums) // true m := { 'one': 1 'two': 2 } println('one' in m) // true println('three' !in m) // true enum Token { plus minus div mult } struct Parser { token Token } parser := Parser{} if parser.token == .plus || parser.token == .minus || parser.token == .div || parser.token == .mult { // ... } if parser.token in [.plus, .minus, .div, .mult] { // ... } mut numbers := [0, 1, 2] for mut num in numbers { num++ } struct SquareIterator { arr []int mut: idx int } fn (mut iter SquareIterator) next() ?int { if iter.idx >= iter.arr.len { return error('') } defer { iter.idx++ } return iter.arr[iter.idx] * iter.arr[iter.idx] } nums := [1, 2, 3, 4, 5] iter := SquareIterator{ arr: nums } for squared in iter { println(squared) } m := { 'one': 1 'two': 2 } for key, value in m { println('$key -> $value') // Output: one -> 1 // two -> 2 } mut sum := 0 mut i := 0 for i <= 100 { sum += i i++ } mut num := 0 for { num += 2 if num >= 10 { break } } for i := 0; i < 10; i += 2 { // Don't print 6 if i == 6 { continue } println(i) } outer: for i := 4; true; i++ { println(i) for { if i < 7 { continue outer } else { break outer } } } match os { 'darwin' { println('macOS.') } 'linux' { println('Linux.') } else { println(os) } } s := match number { 1 { 'one' } 2 { 'two' } else { 'many' } } match true { 2 > 4 { println('if') } 3 == 4 { println('else if') } 2 == 2 { println('else if2') } else { println('else') } } enum Color { red blue green } fn is_red_or_blue(c Color) bool { return match c { .red, .blue { true } // comma can be used to test multiple values .green { false } } } c := `v` typ := match c { `0`...`9` { 'digit' } `A`...`Z` { 'uppercase' } `a`...`z` { 'lowercase' } else { 'other' } } enum State { normal write_log return_error } // write log file and return number of bytes written fn write_log(s State) ?int { mut f := os.create('log.txt')? defer { f.close() } if s == .write_log { // `f.close()` will be called after `f.write()` has been // executed, but before `write_log()` finally returns the // number of bytes written to `main()` return f.writeln('This is a log file') } else if s == .return_error { // the file will be closed after the `error()` function // has returned - so the error message will still report // it as open return error('nothing written; file open: $f.is_opened') } // the file will be closed here, too return 0 } [params] struct ButtonConfig { text string is_disabled bool width int = 70 height int = 20 } struct Button { text string width int height int } fn new_button(c ButtonConfig) &Button { return &Button{ width: c.width height: c.height text: c.text } } button := new_button(text: 'Click me', width: 100) // the height is unset, so it's the default value assert button.height == 20 new_button(ButtonConfig{text:'Click me', width:100}) struct Foo { a int // private immutable (default) mut: b int // private mutable c int // (you can list multiple fields with the same access modifier) pub: d int // public immutable (readonly) pub mut: e int // public, but mutable only in parent module __global: // (not recommended to use, that's why the 'global' keyword starts with __) f int // public and mutable both inside and outside parent module } struct User { age int } fn (u User) can_register() bool { return u.age > 16 } user := User{ age: 10 } println(user.can_register()) // "false" user2 := User{ age: 20 } println(user2.can_register()) // "true" struct Size { mut: width int height int } fn (s &Size) area() int { return s.width * s.height } struct Button { Size title string } mut button := Button{ title: 'Click me' height: 2 } button.width = 3 assert button.area() == 6 assert button.Size.area() == 6 mut button := Button{ Size: Size{ width: 3 height: 2 } } struct Rgba32_Component { r byte g byte b byte a byte } union Rgba32 { Rgba32_Component value u32 } clr1 := Rgba32{ value: 0x008811FF } clr2 := Rgba32{ Rgba32_Component: Rgba32_Component{ a: 128 } } sz := sizeof(Rgba32) unsafe { println('Size: ${sz}B,clr1.b: $clr1.b,clr2.b: $clr2.b') } fn multiply_by_2(mut arr []int) { for i in 0 .. arr.len { arr[i] *= 2 } } mut nums := [1, 2, 3] multiply_by_2(mut nums) println(nums) // "[2, 4, 6]" struct User { name string age int is_registered bool } fn register(u User) User { return User{ ...u is_registered: true } } mut user := User{ name: 'abc' age: 23 } user = register(user) println(user) fn sum(a ...int) int { mut total := 0 for x in a { total += x } return total } println(sum()) // 0 println(sum(1)) // 1 println(sum(2, 3)) // 5 // using array decomposition a := [2, 3, 4] println(sum(...a)) // <-- using prefix ... here. output: 9 b := [5, 6, 7] println(sum(...b)) // output: 18 fn sqr(n int) int { return n * n } fn cube(n int) int { return n * n * n } fn run(value int, op fn (int) int) int { return op(value) } my_int := 1 my_closure := fn [my_int] () { println(my_int) } my_closure() // prints 1 fn new_counter() fn () int { mut i := 0 return fn [mut i] () int { i++ return i } } c := new_counter() println(c()) // 1 println(c()) // 2 println(c()) // 3 mut i := 0 mut ref := &i print_counter := fn [ref] () { println(*ref) } print_counter() // 0 i = 10 print_counter() // 10 struct Foo { abc int } fn (foo &Foo) bar() { println(foo.abc) } struct Node<T> { val T left &Node<T> right &Node<T> } const ( pi = 3.14 world = 'δΈη' ) const e = 2.71828 struct Color { r int g int b int } fn rgb(r int, g int, b int) Color { return Color{ r: r g: g b: b } } const ( numbers = [1, 2, 3] red = Color{ r: 255 g: 0 b: 0 } // evaluate function call at compile-time* blue = rgb(0, 0, 255) ) module mymodule pub const golden_ratio = 1.61803 fn calc() { println(mymodule.golden_ratio) } pub fn say_hi() { println('hello from mymodule!') } fn factorial(n u32) u32 { if dump(n <= 1) { return dump(1) } return dump(n * factorial(n - 1)) } fn init() { // your setup code here ... } struct Dog { breed string } fn (d Dog) speak() string { return 'woof' } struct Cat { breed string } fn (c Cat) speak() string { return 'meow' } // unlike Go and like TypeScript, V's interfaces can define fields, not just methods. interface Speaker { breed string speak() string } fn main() { dog := Dog{'Leonberger'} cat := Cat{'Siamese'} mut arr := []Speaker{} arr << dog arr << cat for item in arr { println('a $item.breed says: $item.speak()') } } pub interface Reader { mut: read(mut buf []byte) ?int } pub interface Writer { mut: write(buf []byte) ?int } // ReaderWriter embeds both Reader and Writer. // The effect is the same as copy/pasting all of the // Reader and all of the Writer methods/fields into // ReaderWriter. pub interface ReaderWriter { Reader Writer } type Filter = fn (string) string fn filter(s string, f Filter) string { return f(s) } my_filter := Filter(uppercase) my_filter := uppercase enum Color { @none red green blue } color := Color.@none enum Cycle { one two three } fn (c Cycle) next() Cycle { match c { .one { return .two } .two { return .three } .three { return .one } } } mut c := Cycle.one for _ in 0 .. 10 { println(c) c = c.next() } struct Empty {} struct Node { value f64 left Tree right Tree } type Tree = Empty | Node // sum up all node values fn sum(tree Tree) f64 { return match tree { Empty { 0 } Node { tree.value + sum(tree.left) + sum(tree.right) } } } fn main() { left := Node{0.2, Empty{}, Empty{}} right := Node{0.3, Empty{}, Node{0.4, Empty{}, Empty{}}} tree := Node{0.5, left, right} println(sum(tree)) // 0.2 + 0.3 + 0.4 + 0.5 = 1.4 } struct Moon {} struct Mars {} struct Venus {} type World = Mars | Moon | Venus fn (m Mars) dust_storm() bool { return true } fn main() { mut w := World(Moon{}) assert w is Moon w = Mars{} // use `as` to access the Mars instance mars := w as Mars if mars.dust_storm() { println('bad weather!') } } if mut w is Mars { assert typeof(w).name == 'Mars' if w.dust_storm() { println('bad weather!') } } fn (m Moon) moon_walk() {} fn (m Mars) shiver() {} fn (v Venus) sweat() {} fn pass_time(w World) { match w { // using the shadowed match variable, in this case `w` (smart cast) Moon { w.moon_walk() } Mars { w.shiver() } else {} } } struct User { id int name string } struct Repo { users []User } fn (r Repo) find_user_by_id(id int) ! User { for user in r.users { if user.id == id { // V automatically wraps this into an option type return user } } return error('User $id not found') } fn main() { repo := Repo{ users: [User{1, 'Andrew'}, User{2, 'Bob'}, User{10, 'Charles'}] } user := repo.find_user_by_id(10) or { println(err) // "User 10 not found" return } println(user.id) // "10" println(user.name) // "Charles" } import net.http fn f(url string) ?string { resp := http.get(url)? return resp.text } resp := http.get(url) or { return err } if resp := http.get('https://google.com') { println(resp.text) // resp is a http.Response, not an optional } else { println(err) } fn do_something(s string) !string { if s == 'foo' { return 'foo' } return error('invalid string') // Could be `return none` as well } a := do_something('foo') or { 'default' } // a will be 'foo' b := do_something('bar') or { 'default' } // b will be 'default' println(a) println(b) struct Repo<T> { db DB } struct User { id int name string } struct Post { id int user_id int title string body string } fn new_repo<T>(db DB) Repo<T> { return Repo<T>{db: db} } // This is a generic function. V will generate it for every type it's used with. fn (r Repo<T>) find_by_id(id int) ?T { table_name := T.name // in this example getting the name of the type gives us the table name return r.db.query_one<T>('select * from $table_name where id = ?', id) } db := new_db() users_repo := new_repo<User>(db) // returns Repo<User> posts_repo := new_repo<Post>(db) // returns Repo<Post> user := users_repo.find_by_id(1)? // find_by_id<User> post := posts_repo.find_by_id(1)? // find_by_id<Post> fn compare<T>(a T, b T) int { if a < b { return -1 } if a > b { return 1 } return 0 } fn p(a f64, b f64) { // ordinary function without return value c := math.sqrt(a * a + b * b) println(c) } fn main() { go p(3, 4) // p will be run in parallel thread } fn get_hypot(a f64, b f64) f64 { c := sqrt(a * a + b * b) return c } fn main() { g := go get_hypot(54.06, 2.08) // spawn thread and get handle to it h1 := get_hypot(2.32, 16.74) // do some other calculation here h2 := g.wait() // get result from spawned thread println('Results: $h1, $h2') // prints `Results: 16.9, 54.1` } fn task(id int, duration int) { println('task $id begin') time.sleep(duration * time.millisecond) println('task $id end') } fn main() { mut threads := []thread{} threads << go task(1, 500) threads << go task(2, 900) threads << go task(3, 100) threads.wait() println('done') } fn expensive_computing(i int) int { return i * i } fn main() { mut threads := []thread int{} for i in 1 .. 10 { threads << go expensive_computing(i) } // Join all tasks r := threads.wait() println('All jobs finished: $r') } ch := chan int{} // unbuffered - "synchronous" ch2 := chan f64{cap: 100} // buffer length 100 ch := chan int{} ch2 := chan f64{} // ... ch.close() // ... m := <-ch or { println('channel has been closed') } // propagate error y := <-ch2 ? fn main() { ch := chan f64{} ch2 := chan f64{} ch3 := chan f64{} mut b := 0.0 c := 1.0 // ... setup go threads that will send on ch/ch2 go fn (the_channel chan f64) { time.sleep(5 * time.millisecond) the_channel <- 1.0 }(ch) go fn (the_channel chan f64) { time.sleep(1 * time.millisecond) the_channel <- 1.0 }(ch2) go fn (the_channel chan f64) { _ := <-the_channel }(ch3) select { a := <-ch { // do something with `a` eprintln('> a: $a') } b = <-ch2 { // do something with predeclared variable `b` eprintln('> b: $b') } ch3 <- c { // do something if `c` was sent time.sleep(5 * time.millisecond) eprintln('> c: $c was send on channel ch3') } 500 * time.millisecond { // do something if no channel has become ready within 0.5s eprintln('> more than 0.5s passed without a channel being ready') } } eprintln('> done') } struct Abc { x int } a := 2.13 ch := chan f64{} res := ch.try_push(a) // try to perform `ch <- a` println(res) l := ch.len // number of elements in queue c := ch.cap // maximum queue length is_closed := ch.closed // bool flag - has `ch` been closed println(l) println(c) mut b := Abc{} ch2 := chan Abc{} res2 := ch2.try_pop(mut b) // try to perform `b = <-ch2` struct St { mut: x int // data to be shared } fn (shared b St) g() { lock b { // read/modify/write b.x } } fn main() { shared a := St{ x: 10 } go a.g() // ... rlock a { // read a.x } } import json struct Foo { x int } struct User { name string [required] age int // Use the `skip` attribute to skip certain fields foo Foo [skip] // If the field name is different in JSON, it can be specified last_name string [json: lastName] } data := '{ "name": "Frodo", "lastName": "Baggins", "age": 25 }' user := json.decode(User, data) or { eprintln('Failed to decode json, error: $err') return } println(user.name) println(user.last_name) println(user.age) // You can also decode JSON arrays: sfoos := '[{"x":123},{"x":456}]' foos := json.decode([]Foo, sfoos)? println(foos[0].x) println(foos[1].x) struct User { name string score i64 } mut data := map[string]int{} user := &User{ name: 'Pierre' score: 1024 } data['x'] = 42 data['y'] = 360 println(json.encode(data)) // {"x":42,"y":360} println(json.encode(user)) // {"name":"Pierre","score":1024} fn test_hello() { assert hello() == 'Hello world' } import strconv fn test_atoi() ? { assert strconv.atoi('1')? == 1 assert strconv.atoi('one')? == 1 // test will fail } fn test_subtest() { res := os.execute('${os.quoted_path(@VEXE)} other_test.v') assert res.exit_code == 1 assert res.output.contains('other_test.v does not exist') } os.execute('${os.quoted_path("{test}. \${another test}. \{and another\}")} other_test.v') struct RefStruct { mut: r &MyStruct } [heap] struct MyStruct { n int } fn main() { m := MyStruct{} mut r := RefStruct{ r: &m } r.g() println('r: $r') } fn (mut r RefStruct) g() { s := MyStruct{ n: 7 } r.f(&s) // reference to `s` inside `r` is passed back to `main() ` } fn (mut r RefStruct) f(s &MyStruct) { r.r = s // would trigger error without `[heap]` } import sqlite // sets a custom table name. Default is struct name (case-sensitive) [table: 'customers'] struct Customer { id int [primary; sql: serial] // a field named `id` of integer type must be the first field name string [nonull] nr_orders int country string [nonull] } db := sqlite.connect('customers.db')? sql db { create table Customer } // select count(*) from customers nr_customers := sql db { select count from Customer } println('number of all customers: $nr_customers') // V syntax can be used to build queries uk_customers := sql db { select from Customer where country == 'uk' && nr_orders > 0 } println(uk_customers.len) for customer in uk_customers { println('$customer.id - $customer.name') } // by adding `limit 1` we tell V that there will be only one object customer := sql db { select from Customer where id == 1 limit 1 } println('$customer.id - $customer.name') // insert a new customer new_customer := Customer{ name: 'Bob' nr_orders: 10 } sql db { insert new_customer into Customer } // clearall clears all bits in the array fn clearall() { } // copy_all recursively copies all elements of the array by their value, // # Some Heading // if `dupes` is false all duplicate values are eliminated in the process. // ---------------------------------------- fn copy_all(dupes bool) { // ... } fn main() { sw := time.new_stopwatch() println('Hello world') println('Greeting the world took: ${sw.elapsed().nanoseconds()}ns') } // allocate 2 uninitialized bytes & return a reference to them mut p := unsafe { malloc(2) } p[0] = `h` // Error: pointer indexing is only allowed in `unsafe` blocks unsafe { p[0] = `h` // OK p[1] = `i` } p++ // Error: pointer arithmetic is only allowed in `unsafe` blocks unsafe { p++ // OK } assert *p == `i` struct Foo { a int b int } assert sizeof(Foo) == 8 assert __offsetof(Foo, a) == 0 assert __offsetof(Foo, b) == 4 #flag -lsqlite3 #include "sqlite3.h" // See also the example from https://www.sqlite.org/quickstart.html struct C.sqlite3 { } struct C.sqlite3_stmt { } type FnSqlite3Callback = fn (voidptr, int, &&char, &&char) int fn C.sqlite3_open(&char, &&C.sqlite3) int fn C.sqlite3_close(&C.sqlite3) int fn C.sqlite3_column_int(stmt &C.sqlite3_stmt, n int) int // ... you can also just define the type of parameter and leave out the C. prefix fn C.sqlite3_prepare_v2(&C.sqlite3, &char, int, &&C.sqlite3_stmt, &&char) int fn C.sqlite3_step(&C.sqlite3_stmt) fn C.sqlite3_finalize(&C.sqlite3_stmt) fn C.sqlite3_exec(db &C.sqlite3, sql &char, cb FnSqlite3Callback, cb_arg voidptr, emsg &&char) int fn C.sqlite3_free(voidptr) fn my_callback(arg voidptr, howmany int, cvalues &&char, cnames &&char) int { unsafe { for i in 0 .. howmany { print('| ${cstring_to_vstring(cnames[i])}: ${cstring_to_vstring(cvalues[i]):20} ') } } println('|') return 0 } fn main() { db := &C.sqlite3(0) // this means `sqlite3* db = 0` // passing a string literal to a C function call results in a C string, not a V string C.sqlite3_open(c'users.db', &db) // C.sqlite3_open(db_path.str, &db) query := 'select count(*) from users' stmt := &C.sqlite3_stmt(0) // NB: you can also use the `.str` field of a V string, // to get its C style zero terminated representation C.sqlite3_prepare_v2(db, &char(query.str), -1, &stmt, 0) C.sqlite3_step(stmt) nr_users := C.sqlite3_column_int(stmt, 0) C.sqlite3_finalize(stmt) println('There are $nr_users users in the database.') // error_msg := &char(0) query_all_users := 'select * from users' rc := C.sqlite3_exec(db, &char(query_all_users.str), my_callback, voidptr(7), &error_msg) if rc != C.SQLITE_OK { eprintln(unsafe { cstring_to_vstring(error_msg) }) C.sqlite3_free(error_msg) } C.sqlite3_close(db) } [export: 'my_custom_c_name'] fn foo() { } $if windows { #include "@VEXEROOT/thirdparty/stdatomic/win/atomic.h" } $else { #include "@VEXEROOT/thirdparty/stdatomic/nix/atomic.h" } // declare functions we want to use - V does not parse the C header fn C.atomic_store_u32(&u32, u32) fn C.atomic_load_u32(&u32) u32 fn C.atomic_compare_exchange_weak_u32(&u32, &u32, u32) bool fn C.atomic_compare_exchange_strong_u32(&u32, &u32, u32) bool const num_iterations = 10000000 // see section "Global Variables" below __global ( atom u32 // ordinary variable but used as atomic ) fn change() int { mut races_won_by_change := 0 for { mut cmp := u32(17) // addressable value to compare with and to store the found value // atomic version of `if atom == 17 { atom = 23 races_won_by_change++ } else { cmp = atom }` if C.atomic_compare_exchange_strong_u32(&atom, &cmp, 23) { races_won_by_change++ } else { if cmp == 31 { break } cmp = 17 // re-assign because overwritten with value of atom } } return races_won_by_change } fn main() { C.atomic_store_u32(&atom, 17) t := go change() mut races_won_by_main := 0 mut cmp17 := u32(17) mut cmp23 := u32(23) for i in 0 .. num_iterations { // atomic version of `if atom == 17 { atom = 23 races_won_by_main++ }` if C.atomic_compare_exchange_strong_u32(&atom, &cmp17, 23) { races_won_by_main++ } else { cmp17 = 17 } desir := if i == num_iterations - 1 { u32(31) } else { u32(17) } // atomic version of `for atom != 23 {} atom = desir` for !C.atomic_compare_exchange_weak_u32(&atom, &cmp23, desir) { cmp23 = 23 } } races_won_by_change := t.wait() atom_new := C.atomic_load_u32(&atom) println('atom: $atom_new, #exchanges: ${races_won_by_main + races_won_by_change}') // prints `atom: 31, #exchanges: 10000000`) println('races won by\n- `main()`: $races_won_by_main\n- `change()`: $races_won_by_change') } import sync __global ( sem sync.Semaphore // needs initialization in `init()` mtx sync.RwMutex // needs initialization in `init()` f1 = f64(34.0625) // explicily initialized shmap shared map[string]f64 // initialized as empty `shared` map f2 f64 // initialized to `0.0` ) fn init() { sem.init(0) mtx.init() } #flag linux -lsdl2 #flag linux -Ivig #flag linux -DCIMGUI_DEFINE_ENUMS_AND_STRUCTS=1 #flag linux -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS=1 #flag linux -DIMGUI_IMPL_API= #pkgconfig r_core #pkgconfig --cflags --libs r_core $if $pkgconfig('mysqlclient') { #pkgconfig mysqlclient } $else $if $pkgconfig('mariadb') { #pkgconfig mariadb } #flag -I @VMODROOT/c #flag @VMODROOT/c/implementation.o #include "header.h" fn main() { // Support for multiple conditions in one branch $if ios || android { println('Running on a mobile device!') } $if linux && x64 { println('64-bit Linux.') } // Usage as expression os := $if windows { 'Windows' } $else { 'UNIX' } println('Using $os') // $else-$if branches $if tinyc { println('tinyc') } $else $if clang { println('clang') } $else $if gcc { println('gcc') } $else { println('different compiler') } $if test { println('testing') } // v -cg ... $if debug { println('debugging') } // v -prod ... $if prod { println('production build') } // v -d option ... $if option ? { println('custom option') } } fn main() { embedded_file := $embed_file('v.png', .zlib) // compressed using zlib os.write_file('exported.png', embedded_file.to_string())? compile_time_env := $env('ENV_VAR') println(compile_time_env) } fn build() string { name := 'Peter' age := 25 numbers := [1, 2, 3] return $tmpl('1.txt') } $if linux { $compile_error('Linux is not supported') } eprintln('file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @MOD + '.' + @FN) import v.vmod vm := vmod.decode( @VMOD_FILE ) or { panic(err) } eprintln('$vm.name $vm.version\n $vm.description') fn main() { $for field in User.fields { $if field.typ is string { println('$field.name is of type string') } } } struct Vec { x int y int } fn (a Vec) str() string { return '{$a.x, $a.y}' } fn (a Vec) + (b Vec) Vec { return Vec{a.x + b.x, a.y + b.y} } fn (a Vec) - (b Vec) Vec { return Vec{a.x - b.x, a.y - b.y} } fn main() { a := Vec{2, 3} b := Vec{4, 5} mut c := Vec{1, 2} println(a + b) // "{6, 8}" println(a - b) // "{-2, -2}" c += a println(c) // "{3, 5}" } a := 100 b := 20 mut c := 0 asm amd64 { mov eax, a add eax, b mov c, eax ; =r (c) as c // output ; r (a) as a // input r (b) as b } println('a: $a') // 100 println('b: $b') // 20 println('c: $c') // 120 // [flag] enables Enum types to be used as bitfields [flag] enum BitField { read write other } fn main() { assert 1 == int(BitField.read) assert 2 == int(BitField.write) mut bf := BitField.read assert bf.has(.read | .other) // test if *at least one* of the flags is set assert !bf.all(.read | .other) // test if *all* of the flags is set bf.set(.write | .other) assert bf.has(.read | .write | .other) assert bf.all(.read | .write | .other) bf.toggle(.other) assert bf == BitField.read | .write assert bf.all(.read | .write) assert !bf.has(.other) } // Calling this function will result in a deprecation warning [deprecated] fn old_function() { } // It can also display a custom deprecation message [deprecated: 'use new_function() instead'] [deprecated_after: '2021-05-27'] fn legacy_function() {} // This function's calls will be inlined. [inline] fn inlined_function() { } // This function's calls will NOT be inlined. [noinline] fn function() { } [if debug] fn foo() { } fn bar() { foo() // will not be called if `-d debug` is not passed } if x { // ... if y { unsafe { goto my_label } } // ... } my_label: