docs: improve the clarity, fix grammar

pull/4771/head
Teymour Aldridge 2020-05-07 11:30:41 +01:00 committed by GitHub
parent 78c292b448
commit 9b0b6ec2db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 77 additions and 77 deletions

View File

@ -4,14 +4,14 @@
V is a statically typed compiled programming language designed for building maintainable software. 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, 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. you can do in V.
@ -24,13 +24,13 @@ fn main() {
} }
``` ```
Functions are declared with `fn`. Return type goes after the function Functions are declared with `fn`. The return type goes after the function
name. In this case `main` doesn't return anything, so the type is name. In this case `main` doesn't return anything, so the return type can be
omitted. 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. to standard output.
`fn main()` declaration can be skipped in one file programs. `fn main()` declaration can be skipped in one file programs.
@ -94,9 +94,9 @@ println(b) // 3
``` ```
Functions can return multiple values. 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 allow other modules to use them, prepend `pub`. The same applies
to consts and types. to constants and types.
```v ```v
pub fn public_function() { pub fn public_function() {
@ -106,7 +106,7 @@ fn private_function() {
} }
``` ```
## Consts & variables ## Constants & variables
```v ```v
name := 'Bob' 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. 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. `:=` is used for declaring and initializing, `=` is used for assigning.
```v ```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. All variables need to be declared in V.
```v ```v
@ -159,8 +159,8 @@ fn main() {
} }
``` ```
In development mode this code will result in an "unused variable" warning. 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 (`v -prod foo.v`) it will not compile at all, like in Go. 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 ```v
fn main() { 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 ```v
bool 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: 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}'`. `'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`. and specify the output format. The compiler takes care of the storage size, so there is no `hd` or `llu`.
```v ```v
@ -227,7 +227,7 @@ println('x = ${x:12.3f}')
println('${item:-20} ${n:20d}') 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 ```v
println('age = ' + age) 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 ## Arrays
@ -301,24 +301,24 @@ users := []User{}
ids := []int{ len: 50, default: 0 } // This creates an array with 50 zeros 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`). `['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. `<<` is an operator that appends a value to the end of the array.
It can also append an entire array. It can also append an entire array.
`.len` field returns the length of the array. Note, that it's a read-only field, `.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`. `val in array` returns true if the array contains `val`.
All arrays can be easily printed with `println(arr)` and converted to a string All arrays can be easily printed with `println(arr)` and converted to a string
with `s := arr.str()`. 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: `.map()` methods:
```v ```v
@ -331,7 +331,7 @@ upper := words.map(it.to_upper())
println(upper) // ['HELLO', 'WORLD'] 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 ## Maps
@ -393,7 +393,7 @@ m := {'one': 1, 'two': 2}
println('one' in m) // true 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 ```v
if parser.token == .plus || parser.token == .minus || 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 ## For loop
@ -463,7 +463,7 @@ for {
println(num) // "10" 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 ```v
for i := 0; i < 10; i++ { 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`. The type of `p` is `&Point`. It's a reference to `Point`.
References are similar to Go pointers and C++ references. 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 ```v
// TODO: this will be implemented later // 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. 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. 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 ```v
fn main() { fn main() {
str := 'hello' str := 'hello'
@ -641,14 +641,15 @@ but a short, preferably one letter long, name.
## Pure functions by default ## 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. and their evaluation has no side effects.
This is achieved by lack of global variables and all function arguments being immutable by default, This is achieved by lack of global variables and all function arguments being immutable by default,
even when references are passed. even when references are passed.
V is not a pure functional language however. V is not a purely functional language however.
It is possible to modify function arguments by using the same keyword `mut`:
It is possible to modify function arguments by using the keyword `mut`:
```v ```v
struct User { 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 Modifying arguments should only be done in performance-critical parts of your application
to reduce allocations and copying. to reduce allocations and copying.
For this reason V doesn't allow to modify primitive args like integers, only 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.
complex types like arrays and maps.
Use `user.register()` or `user = register(user)` Use `user.register()` or `user = register(user)`
instead of `register(mut 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, 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 V can pass it either value or reference. The compiler will determine this by itself,
by the compiler, and the developer doesn't need to think about it. and the developer doesn't need to think about it.
You no longer need to remember whether you should pass the struct by value You no longer need to remember whether you should pass the struct by value
or by reference. 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 `&`: adding `&`:
```v ```v
@ -762,7 +762,7 @@ fn (foo &Foo) bar() {
`foo` is still immutable and can't be changed. For that, `foo` is still immutable and can't be changed. For that,
`(mut foo Foo)` has to be used. `(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: For example, a tree structure definition would look like this:
```v ```v
@ -989,7 +989,7 @@ To check whether a sum type is a certain type, use `is`:
println(expr is IfExpr) println(expr is IfExpr)
``` ```
## Option/Result types & error handling ## Option/Result types and error handling
```v ```v
struct User { 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. 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. 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, 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. 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 `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 Basically the code above is a shorter version of
```v ```v
@ -1065,7 +1065,7 @@ resp := http.get(url) or {
println(resp.body) 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. or Swift's `!`). You have to use `or { panic(err) }` instead.
@ -1095,9 +1095,9 @@ post := posts_repo.find_by_id(1)?
## Concurrency ## Concurrency
The concurrency model is very similar to Go. To run `foo()` concurrently, just 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 in a new system call it with `go foo()`. Right now, it launches the function on a new system
thread. Soon coroutines and the scheduler will be implemented. thread. Soon coroutines and a scheduler will be implemented.
## Decoding JSON ## Decoding JSON
@ -1125,10 +1125,9 @@ println(user.last_name)
println(user.age) 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 `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.
The second argument is the JSON string.
V generates code for JSON encoding and decoding. No runtime reflection is used. This results in much better V generates code for JSON encoding and decoding. No runtime reflection is used. This results in much better
performance. 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 `<some name>_test.v` and test function names must begin with `test_`.
You can also define a special test function: `testsuite_begin`, which will be You can also define a special test function: `testsuite_begin`, which will be
run *before* all other test functions in a `_test.v` file. 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`. 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. You can pass `-stats` to v test, to see more details about the individual tests in each _test.v file.
## Memory management ## Memory management
(Work in progress) (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 during compilation. If your V program compiles, it's guaranteed that it's going
to be leak free. For example: 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. - 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. - 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. - 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 ```v
struct Customer { // struct name has to be the same as the table name for now 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 id int // an field named `id` of integer type must be the first field
name string name string
nr_orders int nr_orders int
country string country string
@ -1271,8 +1271,8 @@ db.insert(new_customer)
## vfmt ## vfmt
You don't need to worry about formatting your code or style guidelines. You don't need to worry about formatting your code or setting style guidelines.
vfmt takes care of that: `vfmt` takes care of that:
```v ```v
v fmt file.v v fmt file.v
@ -1286,7 +1286,7 @@ Always run `v fmt file.v` before pushing your code.
## Writing Documentation ## Writing Documentation
The way it works is very similar to Go. It's very simple: there's no need to 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: 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: You can sort on column 3 (average time per function) using:
`sort -n -k3 profile.txt|tail` `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 ```v
import time import time
fn main(){ 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 - `-L` for adding C library files search paths
- `-D` for setting compile time variables - `-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 ```v
#flag linux -lsdl2 #flag linux -lsdl2
@ -1378,7 +1378,7 @@ NB: For now you have to use one flag per line:
#flag linux -DIMGUI_IMPL_API= #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 * 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 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*`.
- `&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. - `-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. - `-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. - `-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` . 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` . 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 ```v
$if windows { $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. an OS or a `-debug` compilation option.
## Reflection via codegen ## Reflection via codegen
Having built-in JSON support is nice, but V also allows you to create efficient Having built-in JSON support is nice, but V also allows you to create efficient
serializers for anything: serializers for any data format:
```v ```v
// TODO: not implemented yet // TODO: not implemented yet
@ -1535,12 +1535,12 @@ fn main() {
``` ```
Operator overloading goes against V's philosophy of simplicity and predictability. But since 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: in order to improve readability:
`a.add(b).add(c.mul(d))` is a lot less readable than `a + b + c * d`. `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. - It's only possible to overload `+, -, *, /` operators.
- Calling other functions inside operator functions is not allowed. - Calling other functions inside operator functions is not allowed.