diff --git a/doc/docs.md b/doc/docs.md index 2b811a51b9..a76afa912e 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -4,14 +4,14 @@ V is a statically typed compiled programming language designed for building maintainable software. -It's similar to Go and is also influenced by Oberon, Rust, Swift, Python. +It's similar to Go and its design has also been influenced by Oberon, Rust, Swift, and Python. 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. +and by the end of it you will have pretty much learned the entire language. -The language promotes writing simple and clear code with a minimal amount of abstractions. +The language promotes writing simple and clear code with minimal abstraction. -Despite being simple, it gives a lot of power to the developer. Anything you can do in other languages, +Despite being simple, V gives the devloper a lot of power. Anything you can do in other languages, you can do in V. @@ -24,13 +24,13 @@ fn main() { } ``` -Functions are declared with `fn`. Return type goes after the function -name. In this case `main` doesn't return anything, so the type is +Functions are declared with `fn`. The return type goes after the function +name. In this case `main` doesn't return anything, so the return type can be omitted. -Just like in C and all related languages, `main` is an entry point. +As in many other languages (such as C, Go and Rust), `main` is an entry point. -`println` is one of the few built-in functions. It prints the value +`println` is one of the few built-in functions. It prints the value passed to it to standard output. `fn main()` declaration can be skipped in one file programs. @@ -94,9 +94,9 @@ println(b) // 3 ``` Functions can return multiple values. -Functions, like consts, and types, are private (not exported) by default. +Like constants and types, functions are private (not exported) by default. To allow other modules to use them, prepend `pub`. The same applies -to consts and types. +to constants and types. ```v pub fn public_function() { @@ -106,7 +106,7 @@ fn private_function() { } ``` -## Consts & variables +## Constants & variables ```v name := 'Bob' @@ -141,7 +141,7 @@ immutable by default. To be able to change the value of the variable, you have t Try compiling the program above after removing `mut` from the first line. -Please note the difference between `:=` and `=` +Note the (important) difference between `:=` and `=` `:=` is used for declaring and initializing, `=` is used for assigning. ```v @@ -150,7 +150,7 @@ fn main() { } ``` -This code will not compile, because variable `age` is not declared. +This code will not compile, because the variable `age` is not declared. All variables need to be declared in V. ```v @@ -159,8 +159,8 @@ fn main() { } ``` -In development mode this code will result in an "unused variable" warning. -In production mode (`v -prod foo.v`) it will not compile at all, like in Go. +In development mode the compiler will warn you that you haven't used the variable (you'll get an "unused variable" warning). +In production mode (enabled by passing the `-prod` flag to v – `v -prod foo.v`) it will not compile at all (like in Go). ```v fn main() { @@ -171,9 +171,9 @@ fn main() { } ``` -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. +Unlike most languages, variable shadowing is not allowed. Declaring a variable with a name that is already used in a parent scope will cause a compilation error. -## Basic types +## Primitive types ```v bool @@ -219,7 +219,7 @@ Both single and double quotes can be used to denote strings. For consistency, Interpolation syntax is pretty simple. It also works with fields: `'age = $user.age'`. If you need more complex expressions, use `${}`: `'can register = ${user.age > 13}'`. -Format specifiers similar to those in C's `printf()` are supported, too. `f`, `g`, `x`, etc. are optional +Format specifiers similar to those in C's `printf()` are also supported. `f`, `g`, `x`, etc. are optional and specify the output format. The compiler takes care of the storage size, so there is no `hd` or `llu`. ```v @@ -227,7 +227,7 @@ println('x = ${x:12.3f}') println('${item:-20} ${n:20d}') ``` -All operators in V must have values of the same type on both sides. This code will not compile if `age` is an `int`: +All operators in V must have values of the same type on both sides. This code will not compile if `age` is not a string (for example if `age` were an `int`): ```v println('age = ' + age) @@ -270,7 +270,7 @@ fn main() { } ``` -Modules can be imported using keyword `import`. When using types, functions, and consts from other modules, the full path must be specified. In the example above, `name := get_line()` wouldn't work. That means that it's always clear from which module a function is called +Modules can be imported using keyword `import`. When using types, functions, and constants from other modules, the full path must be specified. In the example above, `name := get_line()` wouldn't work. That means that it's always clear from which module a function is called ## Arrays @@ -301,24 +301,24 @@ users := []User{} ids := []int{ len: 50, default: 0 } // This creates an array with 50 zeros ``` -Array type is determined by the first element: `[1, 2, 3]` is an array of ints (`[]int`). +The type of an array is determined by the first element: `[1, 2, 3]` is an array of ints (`[]int`). `['a', 'b']` is an array of strings (`[]string`). -All elements must have the same type. `[1, 'a']` will not compile. +V arrays are homogenous (all elements must have the same type). This means that code like `[1, 'a']` will not compile. `<<` is an operator that appends a value to the end of the array. It can also append an entire array. `.len` 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. +and it can't be modified by the user. Exported fields are read-only by default in V. `val in array` returns true if the array contains `val`. All arrays can be easily printed with `println(arr)` and converted to a string with `s := arr.str()`. -Arrays can be efficiently filtered and mapped with `.filter()` and +Arrays can be efficiently filtered and mapped with the `.filter()` and `.map()` methods: ```v @@ -331,7 +331,7 @@ upper := words.map(it.to_upper()) println(upper) // ['HELLO', 'WORLD'] ``` -`it` is a special variable that refers to an element in filter/map methods. +`it` is a special variable that refers to the element of the array currently being processed in filter/map methods. ## Maps @@ -393,7 +393,7 @@ m := {'one': 1, 'two': 2} println('one' in m) // true ``` -It's also useful for writing more clear and compact boolean expressions: +It's also useful for writing clearer and more compact boolean expressions: ```v if parser.token == .plus || parser.token == .minus || @@ -406,7 +406,7 @@ if parser.token in [.plus, .minus, .div, .mult] { } ``` -V optimizes such expressions, so both `if` statements above produce the same machine code, no arrays are created. +V optimizes such expressions, so both `if` statements above produce the same machine code and no arrays are created. ## For loop @@ -463,7 +463,7 @@ for { println(num) // "10" ``` -The condition can be omitted, this results in an infinite loop. +The condition can be omitted, resulting in an infinite loop. ```v for i := 0; i < 10; i++ { @@ -552,7 +552,7 @@ println(p.x) The type of `p` is `&Point`. It's a reference to `Point`. References are similar to Go pointers and C++ references. -V doesn't have subclassing, but it supports embedded structs: +V doesn't allow subclassing, but it supports embedded structs: ```v // TODO: this will be implemented later @@ -602,7 +602,7 @@ pub: It's easy to see from this definition that `string` is an immutable type. The byte pointer with the string data is not accessible outside `builtin` at all. -`len` field is public, but not mutable: +The `len` field is public, but immutable: ```v fn main() { str := 'hello' @@ -641,14 +641,15 @@ but a short, preferably one letter long, name. ## Pure functions by default -V functions are pure by default, meaning that their return values are only determined by their arguments, +V functions are pure by default, meaning that their return values are a function of their arguments only, and their evaluation has no side effects. This is achieved by lack of global variables and all function arguments being immutable by default, even when references are passed. -V is not a pure functional language however. -It is possible to modify function arguments by using the same keyword `mut`: +V is not a purely functional language however. + +It is possible to modify function arguments by using the keyword `mut`: ```v struct User { @@ -688,8 +689,7 @@ 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. -For this reason V doesn't allow to modify primitive args like integers, only -complex types like arrays and maps. +For this reason V doesn't allow the modification of arguments with primative types such as integers. Only more complex types such as arrays and maps may be modified. Use `user.register()` or `user = register(user)` instead of `register(mut user)`. @@ -743,14 +743,14 @@ fn bar_function(foo Foo) { } ``` -If a function argument is immutable like `foo` in the examples above, -V can pass it by value or by reference. The decision is made -by the compiler, and the developer doesn't need to think about it. +If a function argument is immutable (like `foo` in the examples above) +V can pass it either value or reference. The compiler will determine this by itself, +and the developer doesn't need to think about it. You no longer need to remember whether you should pass the struct by value or by reference. -There's a way to ensure that the struct is always passed by reference by +You can ensure that the struct is always passed by reference by adding `&`: ```v @@ -762,7 +762,7 @@ fn (foo &Foo) bar() { `foo` is still immutable and can't be changed. For that, `(mut foo Foo)` has to be used. -In general, V references are similar to Go pointers and C++ references. +In general, V's references are similar to Go pointers and C++ references. For example, a tree structure definition would look like this: ```v @@ -989,7 +989,7 @@ To check whether a sum type is a certain type, use `is`: println(expr is IfExpr) ``` -## Option/Result types & error handling +## Option/Result types and error handling ```v struct User { @@ -1029,10 +1029,10 @@ fn main() { V combines `Option` and `Result` into one type, so you don't need to decide which one to use. -The amount of work required to "upgrade" a function to an optional function is minimal: +The amount of work required to "upgrade" a function to return an instance of `Option` is minimal: you have to add a `?` to the return type and return an error when something goes wrong. -If you don't need to return an error message, you can simply `return none` (more efficient equivalent of `return error("")`). +If you don't need to return an error message, you can simply `return none` (this is equivalent to `return error("")`). 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. @@ -1055,7 +1055,7 @@ println(resp.body) ``` `http.get` returns `?http.Response`. It was called with `?`, so the error is propagated to the calling function -(which must return an optional) or in case of `main()` leads to a panic. +(which must return an optional) or if it is used in the `main()` function will cause a panic. Basically the code above is a shorter version of ```v @@ -1065,7 +1065,7 @@ resp := http.get(url) or { println(resp.body) ``` -V does not have a way to force unwrap an optional (like Rust's `unwrap()` +V does not have a way to forcibly unwrap an optional (like Rust's `unwrap()` or Swift's `!`). You have to use `or { panic(err) }` instead. @@ -1095,9 +1095,9 @@ post := posts_repo.find_by_id(1)? ## Concurrency -The concurrency model is very similar to Go. To run `foo()` concurrently, just -call it with `go foo()`. Right now, it launches the function in a new system -thread. Soon coroutines and the scheduler will be implemented. +V's model of concurrency is very similar to Go's. To run `foo()` concurrently, just +call it with `go foo()`. Right now, it launches the function on a new system +thread. Soon coroutines and a scheduler will be implemented. ## Decoding JSON @@ -1125,10 +1125,9 @@ println(user.last_name) println(user.age) ``` -JSON is very popular nowadays, that's why JSON support is built in. +Because of the ubiquitous nature of JSON, support is built into V. -The first argument of the `json.decode` function is the type to decode to. -The second argument is the JSON string. +the `json.decode` function takes two arguments: the first argument of the `json.decode` function is the type into which the JSON value should be decoded and the second is a string containing the JSON data. V generates code for JSON encoding and decoding. No runtime reflection is used. This results in much better performance. @@ -1147,9 +1146,9 @@ fn test_hello() { } ``` -`assert` keyword can be used outside of tests as well. +The `assert` keyword can be used outside of tests as well. -All test functions have to be placed in `*_test.v` files and begin with `test_`. +All test functions have to be placed in files named `_test.v` and test function names must begin with `test_`. You can also define a special test function: `testsuite_begin`, which will be run *before* all other test functions in a `_test.v` file. @@ -1161,14 +1160,15 @@ To run the tests do `v hello_test.v`. To test an entire module, do `v test mymodule`. -You can also do `v test .` to test everything inside your curent folder (and underneath it). +You can also do `v test .` to test everything inside your curent folder (and subdirectories). You can pass `-stats` to v test, to see more details about the individual tests in each _test.v file. ## Memory management (Work in progress) -There's no garbage collection or reference counting. V cleans everything up + +V doesn't use garbage collection or reference counting. The compiler cleans everything up during compilation. If your V program compiles, it's guaranteed that it's going to be leak free. For example: @@ -1234,13 +1234,13 @@ The benefits of V ORM: - One syntax for all SQL dialects. Migrating to a different database becomes much easier. - Queries are constructed with V syntax. There's no need to learn another syntax. -- Safety. It's impossible to construct a SQL query with an injection. +- Safety. All queries are automatically santised to prevent SQL injection. - Compile time checks. No more typos that can only be caught at runtime. -- Readability and simplicity. You don't need to manually parse the results and construct objects. +- Readability and simplicity. You don't need to manually parse the results of a query and then manually construct objects from the parsed results. ```v -struct Customer { // struct name has to be the same as the table name for now - id int // an integer id must be the first field +struct Customer { // struct name has to be the same as the table name (for now) + id int // an field named `id` of integer type must be the first field name string nr_orders int country string @@ -1271,8 +1271,8 @@ db.insert(new_customer) ## vfmt -You don't need to worry about formatting your code or style guidelines. -vfmt takes care of that: +You don't need to worry about formatting your code or setting style guidelines. +`vfmt` takes care of that: ```v v fmt file.v @@ -1286,7 +1286,7 @@ Always run `v fmt file.v` before pushing your code. ## Writing Documentation The way it works is very similar to Go. It's very simple: there's no need to -write separate documentation for your code, vdoc will generate it from the source code. +write documentation seperately for your code, vdoc will generate it from docstrings in the source code. Documentation for each function/type/const must be placed right before the declaration: @@ -1317,7 +1317,7 @@ d) the name of the v function You can sort on column 3 (average time per function) using: `sort -n -k3 profile.txt|tail` -You can also use stop watches to measure just portions of your code explicitly: +You can also use stopwatches to measure just portions of your code explicitly: ```v import time fn main(){ @@ -1366,9 +1366,9 @@ Add `#flag` directives to the top of your V files to provide C compilation flags - `-L` for adding C library files search paths - `-D` for setting compile time variables -You can use different flags for different targets. Right now, `linux`, `darwin` , `freebsd`, and `windows` are supported. +You can use different flags for different targets. Currently the `linux`, `darwin` , `freebsd`, and `windows` flags are supported. -NB: For now you have to use one flag per line: +NB: Each flag must go on its own line (for now) ```v #flag linux -lsdl2 @@ -1378,7 +1378,7 @@ NB: For now you have to use one flag per line: #flag linux -DIMGUI_IMPL_API= ``` -You can also add C code, in your V module. For example, lets say that your C code is located in a folder named 'c' inside your module folder. Then: +You can also include C code directly in your V module. For example, let's say that your C code is located in a folder named 'c' inside your module folder. Then: * Put a v.mod file inside the toplevel folder of your module (if you created your module with `v create` you already have v.mod file). For @@ -1431,27 +1431,27 @@ V has these types for easier interoperability with C: - `charptr` for C's `char*`. - `&charptr` for C's `char**` -To cast `voidptr` to V references, use `user := &User(user_void_ptr)`. +To cast a `voidptr` to a V reference, use `user := &User(user_void_ptr)`. -`voidptr` can also be dereferenced to V structs by casting: `user := User(user_void_ptr)`. +`voidptr` can also be dereferenced into a V struct through casting: `user := User(user_void_ptr)`. -Check out [socket.v for an example of calling C code from V](https://github.com/vlang/v/blob/master/vlib/net/socket.v) . +[Socket.v has an example which calls C code from V](https://github.com/vlang/v/blob/master/vlib/net/socket.v) . -To debug issues with the generated C code, you can pass these flags: +To debug issues in the generated C code, you can pass these flags: - `-cg` - produces a less optimized executable with more debug information in it. - `-keepc` - keep the generated C file, so your debugger can also use it. - `-showcc` - prints the C command that is used to build the program. -For best debugging experience, you can pass all of them at the same time: `v -cg -keepc -showcc yourprogram.v` , then just run your debugger (gdb/lldb) or IDE with the produced executable `yourprogram`. +For the best debugging experience, you can pass all of them at the same time: `v -cg -keepc -showcc yourprogram.v` , then just run your debugger (gdb/lldb) or IDE on the produced executable `yourprogram`. -If you just want to inspect the generated C code, without compiling it further, you can also use: `-o file.c`. This will make V produce the `file.c` then stop. +If you just want to inspect the generated C code, without further compilation, you can also use the `-o` flag (e.g. `-o file.c`). This will make V produce the `file.c` then stop. If you want to see the generated C source code for *just* a single C function, for example `main`, you can use: `-printfn main -o file.c` . To see a detailed list of all flags that V supports, use `v help`, `v help build`, `v help build-c` . -## Compile time if +## Conditional compilation ```v $if windows { @@ -1469,13 +1469,13 @@ $if debug { } ``` -Compile time `if` starts with a `$`. Right now it can only be used to detect +If you want an `if` to be evaluated at compile time it must be prefixed with a `$` sign. Right now it can only be used to detect an OS or a `-debug` compilation option. ## Reflection via codegen Having built-in JSON support is nice, but V also allows you to create efficient -serializers for anything: +serializers for any data format: ```v // TODO: not implemented yet @@ -1535,12 +1535,12 @@ fn main() { ``` 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 +scientific and graphical applications are among V's domains, operator overloading is an important feature to have in order to improve readability: `a.add(b).add(c.mul(d))` is a lot less readable than `a + b + c * d`. -To improve safety and maintainability, operator overloading has several limitations: +To improve safety and maintainability, operator overloading is limited: - It's only possible to overload `+, -, *, /` operators. - Calling other functions inside operator functions is not allowed.