docs: improve the clarity, fix grammar
parent
78c292b448
commit
9b0b6ec2db
152
doc/docs.md
152
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 `<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
|
||||
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:
|
||||
|
||||
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue