Reduce long lines (#176)

pull/179/head^2
Marco Ieni 3 years ago committed by GitHub
parent 5fedf5aa29
commit 76ae5bd896
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,3 +1,6 @@
---
MD004: false
MD013: false
MD010:
code_blocks: false
MD013:
line_length: 300

@ -1,6 +1,9 @@
# Functional Usage of Rust
Rust is an imperative language, but it follows many functional programming paradigms. One of the biggest hurdles to understanding functional programs when coming from an imperative background is the shift in thinking. Imperative programs describe __how__ to do something, whereas declarative programs describe __what__ to do. Let's sum the numbers from 1 to 10 to show this.
Rust is an imperative language, but it follows many functional programming paradigms.
One of the biggest hurdles to understanding functional programs when coming from an imperative background is the shift in thinking.
Imperative programs describe __how__ to do something, whereas declarative programs describe __what__ to do.
Let's sum the numbers from 1 to 10 to show this.
## Imperative
@ -12,7 +15,11 @@ for i in 1..11 {
println!("{}", sum);
```
With imperative programs, we have to play compiler to see what is happening. Here, we start with a `sum` of `0`. Next, we iterate through the range from 1 to 10. Each time through the loop, we add the corresponding value in the range. Then we print it out.
With imperative programs, we have to play compiler to see what is happening.
Here, we start with a `sum` of `0`.
Next, we iterate through the range from 1 to 10.
Each time through the loop, we add the corresponding value in the range.
Then we print it out.
| `i` | `sum` |
|:---:|:-----:|
@ -35,9 +42,14 @@ This is how most of us start out programming. We learn that a program is a set o
println!("{}", (1..11).fold(0, |a, b| a + b));
```
Whoa! This is really different! What's going on here? Remember that with declarative programs we are describing __what__ to do, rather than __how__ to do it. `fold` is a function that [composes](https://en.wikipedia.org/wiki/Function_composition) functions. The name is a convention from Haskell.
Whoa! This is really different! What's going on here? Remember that with declarative programs we are describing __what__ to do, rather than __how__ to do it.
`fold` is a function that [composes](https://en.wikipedia.org/wiki/Function_composition) functions. The name is a convention from Haskell.
Here, we are composing functions of addition (this closure: `|a, b| a + b)`) with a range from 1 to 10. The `0` is the starting point, so `a` is `0` at first. `b` is the first element of the range, `1`. `0 + 1 = 1` is the result. So now we `fold` again, with `a = 1`, `b = 2` and so `1 + 2 = 3` is the next result. This process continues until we get to the last element in the range, `10`.
Here, we are composing functions of addition (this closure: `|a, b| a + b)`) with a range from 1 to 10.
The `0` is the starting point, so `a` is `0` at first.
`b` is the first element of the range, `1`. `0 + 1 = 1` is the result.
So now we `fold` again, with `a = 1`, `b = 2` and so `1 + 2 = 3` is the next result.
This process continues until we get to the last element in the range, `10`.
| `a` | `b` | result |
|:---:|:---:|:------:|

@ -27,8 +27,14 @@ fn main(s: a::S) {
## Discussion
Adding a field to a struct is a mostly backwards compatible change. However, if a client uses a pattern to deconstruct a struct instance, they might name all the fields in the struct and adding a new one would break that pattern. The client could name some of the fields and use `..` in the pattern, in which case adding another field is backwards compatible. Making at least one of the struct's fields private forces clients to use the latter form of patterns, ensuring that the struct is future-proof.
Adding a field to a struct is a mostly backwards compatible change.
However, if a client uses a pattern to deconstruct a struct instance, they might name all the fields in the struct and adding a new one would break that pattern.
The client could name some of the fields and use `..` in the pattern, in which case adding another field is backwards compatible.
Making at least one of the struct's fields private forces clients to use the latter form of patterns, ensuring that the struct is future-proof.
The downside of this approach is that you might need to add an otherwise unneeded field to the struct. You can use the `()` type so that there is no runtime overhead and prepend `_` to the field name to avoid the unused field warning.
The downside of this approach is that you might need to add an otherwise unneeded field to the struct.
You can use the `()` type so that there is no runtime overhead and prepend `_` to the field name to avoid the unused field warning.
If Rust allowed private variants of enums, we could use the same trick to make adding a variant to an enum backwards compatible. The problem there is exhaustive match expressions. A private variant would force clients to have a `_` wildcard pattern.
If Rust allowed private variants of enums, we could use the same trick to make adding a variant to an enum backwards compatible.
The problem there is exhaustive match expressions.
A private variant would force clients to have a `_` wildcard pattern.

@ -4,17 +4,22 @@
Prefer small crates that do one thing well.
Cargo and crates.io make it easy to add third-party libraries, much more so than in say C or C++. Moreover, since packages on crates.io cannot be edited or removed after publication, any build that works now should continue to work in the future. We should take advantage of this tooling, and use smaller, more fine-grained dependencies.
Cargo and crates.io make it easy to add third-party libraries, much more so than in say C or C++.
Moreover, since packages on crates.io cannot be edited or removed after publication, any build that works now should continue to work in the future.
We should take advantage of this tooling, and use smaller, more fine-grained dependencies.
## Advantages
* Small crates are easier to understand, and encourage more modular code.
* Crates allow for re-using code between projects. For example, the `url` crate was developed as part of the Servo browser engine, but has since found wide use outside the project.
* Crates allow for re-using code between projects.
For example, the `url` crate was developed as part of the Servo browser engine, but has since found wide use outside the project.
* Since the compilation unit of Rust is the crate, splitting a project into multiple crates can allow more of the code to be built in parallel.
## Disadvantages
* This can lead to "dependency hell", when a project depends on multiple conflicting versions of a crate at the same time. For example, the `url` crate has both versions 1.0 and 0.5. Since the `Url` from `url:1.0` and the `Url` from `url:0.5` are different types, an HTTP client that uses `url:0.5` would not accept `Url` values from a web scraper that uses `url:1.0`.
* This can lead to "dependency hell", when a project depends on multiple conflicting versions of a crate at the same time.
For example, the `url` crate has both versions 1.0 and 0.5.
Since the `Url` from `url:1.0` and the `Url` from `url:0.5` are different types, an HTTP client that uses `url:0.5` would not accept `Url` values from a web scraper that uses `url:1.0`.
* Packages on crates.io are not curated. A crate may be poorly written, have unhelpful documentation, or be outright malicious.
* Two small crates may be less optimized than one large one, since the compiler does not perform link-time optimization (LTO) by default.

@ -2,7 +2,10 @@
## Description
If you have `unsafe` code, create the smallest possible module that can uphold the needed invariants to build a minimal safe interface upon the unsafety. Embed this into a larger module that contains only safe code and presents an ergonomic interface. Note that the outer module can contain unsafe functions and methods that call directly into the unsafe code. Users may use this to gain speed benefits.
If you have `unsafe` code, create the smallest possible module that can uphold the needed invariants to build a minimal safe interface upon the unsafety.
Embed this into a larger module that contains only safe code and presents an ergonomic interface.
Note that the outer module can contain unsafe functions and methods that call directly into the unsafe code.
Users may use this to gain speed benefits.
## Advantages
@ -17,7 +20,9 @@ If you have `unsafe` code, create the smallest possible module that can uphold t
## Examples
* The [`toolshed`](https://docs.rs/toolshed) crate contains its unsafe operations in submodules, presenting a safe interface to users.
* `std`s `String` class is a wrapper over `Vec<u8>` with the added invariant that the contents must be valid UTF-8. The operations on `String` ensure this behavior. However, users have the option of using an `unsafe` method to create a `String`, in which case the onus is on them to guarantee the validity of the contents.
* `std`s `String` class is a wrapper over `Vec<u8>` with the added invariant that the contents must be valid UTF-8.
The operations on `String` ensure this behavior.
However, users have the option of using an `unsafe` method to create a `String`, in which case the onus is on them to guarantee the validity of the contents.
## See also

Loading…
Cancel
Save