Giter Site home page Giter Site logo

r4cppp's Introduction

Rust For Systems Programmers

A Rust tutorial for experienced C and C++ programmers.

Jump to contents. Jump to contributing.

This tutorial is intended for programmers who already know how pointers and references work and are used to systems programming concepts such as integer widths and memory management. We intend to cover, primarily, the differences between Rust and C++ to get you writing Rust programs quickly without lots of fluff you probably already know.

Hopefully, Rust is a pretty intuitive language for C++ programmers. Most of the syntax is pretty similar. The big difference (in my experience) is that the sometimes vague concepts of good systems programming are strictly enforced by the compiler. This can be infuriating at first - there are things you want to do, but the compiler won't let you (at least in safe code), and sometimes these things are safe, but you can't convince the compiler of that. However, you'll quickly develop a good intuition for what is allowed. Communicating your own notions of memory safety to the compiler requires some new and sometimes complicated type annotations. But if you have a strong idea of lifetimes for your objects and experience with generic programming, they shouldn't be too tough to learn.

This tutorial started as a series of blog posts. Partly as an aid for me (@nrc) learning Rust (there is no better way to check that you have learnt something than to try and explain it to somebody else) and partly because I found the existing resources for learning Rust unsatisfactory - they spent too much time on the basics that I already knew and used higher level intuitions to describe concepts that could better be explained to me using lower level intuitions. Since then, the documentation for Rust has got much better, but I still think that existing C++ programmers are an audience who are a natural target for Rust, but are not particularly well catered for.

Contents

  1. Introduction - Hello world!
  2. Control flow
  3. Primitive types and operators
  4. Unique pointers
  5. Borrowed pointers
  6. Rc and raw pointers
  7. Data types
  8. Destructuring pt 1
  9. Destructuring pt 2
  10. Arrays and vecs
  11. Graphs and arena allocation
  12. Closures and first-class functions

Other resources

  • The Rust book/guide - the best place for learning Rust in general and probably the best place to go for a second opinion on stuff here or for stuff not covered.
  • Rust API documentation - detailed documentation for the Rust libraries.
  • The Rust reference manual - a little out of date in places, but thorough; good for looking up details.
  • Discuss forum - general forum for discussion or questions about using and learning Rust.
  • StackOverflow Rust questions - answers to many beginner and advanced questions about Rust, but be careful though - Rust has changed a lot over the years and some of the answers might be very out of date.
  • A Firehose of Rust - a recorded talk introducing C++ programmers to how lifetimes, mutable aliasing, and move semantics work in Rust

Contributing

Yes please!

If you spot a typo or mistake, please submit a PR, don't be shy! Please feel free to file an issue for larger changes or for new chapters you'd like to see. I'd also be happy to see re-organisation of existing work or expanded examples, if you feel the tutorial could be improved in those ways.

If you'd like to contribute a paragraph, section, or chapter please do! If you want ideas for things to cover, see the list of issues, in particular those tagged new material. If you're not sure of something, please get in touch by pinging me here (@nrc) or on irc (nrc, on #rust or #rust-internals).

Style

Obviously, the intended audience is C++ programmers. The tutorial should concentrate on things that will be new to experienced C++ programmers, rather than a general audience (although, I don't assume the audience is familiar with the most recent versions of C++). I'd like to avoid too much basic material and definitely avoid too much overlap with other resources, in particular the Rust guide/book.

Work on edge case use cases (e.g., using a different build system from Cargo, or writing syntax extensions, using unstable APIs) is definitely welcome, as is in-depth work on topics already covered at a high level.

I'd like to avoid recipe-style examples for converting C++ code to Rust code, but small examples of this kind are OK.

Use of different formats (e.g., question and answer/FAQs, or larger worked examples) are welcome.

I don't plan on adding exercises or suggestions for mini-projects, but if you're interested in that, let me know.

I'm aiming for a fairly academic tone, but not too dry. All writing should be in English (British English, not American English; although I would be very happy to have localisations/translations into any language, including American English) and be valid GitHub markdown. For advice on writing style, grammar, punctuation, etc. see the Oxford Style Manual or The Economist Style Guide. Please limit width to 80 columns. I am a fan of the Oxford comma.

Don't feel like work has to be perfect to be submitted, I'm happy to edit and I'm sure other people will be in the future.

r4cppp's People

Contributors

aakshintala avatar alecroy avatar andidog avatar anuragsoni avatar aserebryakov avatar asmaloney avatar chrahunt avatar chris-sharpe avatar danakj avatar daverigby avatar eush77 avatar franklinyu avatar frankosterfeld avatar iirelu avatar justinian avatar kigawas avatar liamsi avatar ludwikjaniuk avatar maksimryndin avatar md81544 avatar mulkieran avatar nrc avatar pixelcmtd avatar raslanove avatar scls19fr avatar sedrik avatar srgom avatar synecdoche avatar thermalcat avatar tshepang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

r4cppp's Issues

make_unique call typo

In the "Unique pointers" chapter, in the first reference, there is an example of calling make_unique.
const auto x = std::make_unique<const int>{75};
It uses curly braces instead of parentheses, which won't compile.

Methods on structs

In the section on data types it states:

A rust struct is similar to a C struct or a C++ struct without methods. Simply a list of named fields. The syntax is best seen with an example:

This statement is misleading because it suggests that methods can not be defined for a struct, while methods can be defined via impl blocks. There is a brief mention of this possibility with:

Behaviour is defined by functions and those can be defined in traits and impls

However, this suggests the impls would define functions rather than methods, while in fact impls can define both.

For reference here is a short example outlining the type of functionality I am describing.

struct Example {
    foo: i16,
    bar: i16,
}

impl Example {
    fn baz(&self) -> i16 {
        self.foo + self.bar
    }
}

fn main() {
    let ex = Example {
        foo: 3,
        bar: -1,
    };
    println!("{}", ex.baz());
}

This will print 2. I believe a section on this functionality should be added as it is critical to creating useful abstractions.

Description of slice is misleading

The chapter about slices https://github.com/nrc/r4cppp/blob/master/arrays.md#slices uses wrong comparisons. It states

A slice in Rust is just an array whose length is not known at compile time.

But the rust documentation about slices says https://doc.rust-lang.org/std/slice/

A dynamically-sized view into a contiguous sequence, [T].

So a rust slice is similar to a C++ std:span https://en.cppreference.com/w/cpp/container/span and not similar to a rust array (a value) or to an C/C++ array (only a pointer).

Compilation as PDF file

Hello,

it will be nice to have a PDF version of this document.

Maybe you should consider using Gitbook https://www.gitbook.com/ (online ... but I wonder if that's not a paid service even for public document)
Gitbook can also be used offline (it's a npm tool)

An other option could be to use pandoc https://pandoc.org/

What is your opinion?

Kind regards

Calling rust code from C++ and vice versa

For a C++ programmer it is very interesting to see how easy rust and C (and C++) integrate. Most of the time one will start with existing C/C++ code and does not have the luxury to start with empty code base. Several tutorials in this direction exist already. Still, it would be very nice to see a simple example and probably link to more details (https://doc.rust-lang.org/book/ffi.html ?)

Bad example in "Borrowed Pointers"?

The example given is:

fn foo() {
    let mut x = 5;            // type: i32
    {
        let y = &x;           // type: &i32
        //x = 4;              // Error - x has been borrowed
        println!("{}", x);    // Ok - x can be read
    }
    x = 4;                    // OK - y no longer exists
}

But when I tested this, uncommenting the x = 4 line, it built and ran just fine. The same was true for the next example where y = &mut x: when I uncommented the two releavant lines it still ran.

I think either this is a bad example of the concept you were trying to communicate (borrowed values becoming temporarily immutable), or the concept has been changed over time and the material should be updated.

HOWEVER I am just learning Rust, so I may be utterly mistaken :)

Accessing tuple elements using dot notation

In the "Data Types" section, a way of accessing the elements of a tuple discussed in this tutorial is through destructuring. Under "Tuple structs", it is suggested that this is the only way of accessing tuple elements:

Their fields must be accessed by destructuring (like a tuple), rather than by name.

However, there is another way of accessing tuple elements: through "dot notation". Tuple elements can be accessed directly by using a period (.) followed by the index of the value. For example:

fn bar(x: (i32, i32)) {
    println!("x was ({}, {})", x.0, x.1); // Note the `x.0` and `x.1`.
}

This can also be applied to tuple structs:

struct IntPoint (i32, i32);

fn foo(x: IntPoint) {
    println!("x was ({}, {})", x.0, x.1); // Note the `x.0` and `x.1`.
}

It is quite intriguing to me as to why this is left out, because this syntax is encountered early on in the Rust Programming Language book.

Make this a pretty website

With a URL and rendered pages, rather than a plain GH repo. I believe GH or someone else provides some tools for this (gitbook?) so it shouldn't be too hard

Compile error in enums code

In https://github.com/nrc/r4cppp/blob/master/data-types.md you write:

enum Expr {
    Add(i32, i32),
    Or(bool, bool),
    Lit(i32)
}

fn foo() {
    let x = Or(true, false);   // x has type Expr
}

This code throws the following errors:

error[E0425]: cannot find function, tuple struct or tuple variant 'Or' in this scope
   --> enums.rs:10:13
    |
10  |     let x = Or(true, false); // x has type Expr
    |             ^^
    |
help: a tuple variant with a similar name exists
    |
10  |     let x = Ok(true, false); // x has type Expr
    |             ^^
help: possible candidate is found in another module, you can import it into scope
    |
1   | use Expr::Or;
    |

error: aborting due to previous error

For more information about this error, try 'rustc --explain E0425'..

rustc 1.42.0 (b8cedc004 2020-03-09)

Fix: Add namespace
let x = Expr::Or(true, false)

Same on the snippet below:

fn bar(e: Expr) {
    match e {
        Add(x, y) => println!("An `Add` variant: {} + {}", x, y),
        Or(..) => println!("An `Or` variant"),
        _ => println!("Something else (in this case, a `Lit`)"),
    }
}

Same fix. Alternative:

use Expr::Add;
use Expr::Or;

Rephrase tutorial as rust 4 c++-03 programmers

As a C++ programmer the tutorial felt very off because it focus heavily on C++03 (like the style section briefly mentions). It might be worth it to put this up-front, so that it is clear from the very beginning.

Not the most obvious way to do graphs

You've left out what is probably the most common and obvious way to do graphs in practice in Rust, use identity keys:

#[derive(Copy, Clone, Eq, PartialEq, Hash)]
struct NodeID(u32);

struct Node {
    datum: &'static str,
    edges: Vec<NodeID>,
}

struct Graph {
    nodes: HashMap<NodeID, Node>, // or Vec if you never delete Nodes
}

Not a lot of overhead .. vastly less headaches.

UnsafeCell

I want to cover UnsafeCell, and I think the tutorial on RefCell and/or raw pointers is the best place to do that.

Modules

And imports (including list imports, globs, self in import paths, parent imports).

Paths (including absolute vs relative paths).

Trait objects

see also #2 on traits and generics. Should also cover DST, to some extent

Named and parametric lifetimes

Should also cover lifetime elision. I prefer to cover lifetime params in depth before getting on to the elision rules.

Not sure about the ordering with this tut. On one hand I want it to come pretty soon after borrowed references. OTOH, covering some more of the basics first might actually be more useful, but then we get into tricky error messages and elision issues.

Use relative links

Rather than absolute ones. Useful for publishing the tutorial as a website.

I think there are only links on the contents page, but maybe some elsewhere.

for index for indices loop example issue

working with for .. index loop example.

$ rustc --version
rustc 1.12.0-nightly (9316ae515 2016-07-24)
$

fn print_all( all: Vec ){
for i in ..all.len() {
println!("{}: {}", i, all.get(i));
}
}

fn main() {
}
`
the compiler error seen is

for_idx.rs:4:2: 6:3 error: the trait bound std::ops::RangeTo<usize>: std::iter::Iterator is not satisfied [E0277]
for_idx.rs:4 for i in ..all.len() {
^
for_idx.rs:4:2: 6:3 help: run rustc --explain E0277 to see a detailed explanation
for_idx.rs:4:2: 6:3 note: std::ops::RangeTo<usize> is not an iterator; maybe try calling .iter() or a similar method
for_idx.rs:4:2: 6:3 note: required by std::iter::IntoIterator::into_iter
for_idx.rs:5:25: 5:35 error: the trait bound std::option::Option<&i32>: std::fmt::Display is not satisfied [E0277]
for_idx.rs:5 println!("{}: {}", i, all.get(i));
^~~~~~~~~~
:2:27: 2:58 note: in this expansion of format_args!
:3:1: 3:54 note: in this expansion of print! (defined in )
for_idx.rs:5:3: 5:37 note: in this expansion of println! (defined in )
for_idx.rs:5:25: 5:35 help: run rustc --explain E0277 to see a detailed explanation
for_idx.rs:5:25: 5:35 note: std::option::Option<&i32> cannot be formatted with the default formatter; try using :? instead if you are using a format string
for_idx.rs:5:25: 5:35 note: required by std::fmt::Display::fmt
error: aborting due to 2 previous errors

What's cf?

At the end of Chapter 5 Borrowing (emphasis mine):

These have the syntax &'a T (_cf_ &T).

What's cf? The next sentence makes sense to me, so I guess I'm just being thrown by a contraction or abbreviation that is escaping me?

P.S. Thank you _so much_ for this! As an experienced C++ programmer, this is exactly the perspective for an intro to Rust I've been looking for.

Suspicious typo in Data Types

In the chapter: Data Types

Sometimes whilst an object is logically mutable, it has parts which need to be internally mutable.

It should be ... is logically immutable ... according to the example.

Strings and chars

str, String, char, [u8]. Can probably skip most unicode background, but needs to mention utf8.

`int` is not a valid rust type

In destructuring.md you make lots of mention of int. However, this isn't a valid rust primitive type which could be a bit confusing. I suspect you probably meant to use isize.

NOTE: technically it would be possible to make your code correct by a hidden type alias .. but it wouldn't be following the naming conventions.

Revise chapter "Graphs and arena allocation"

Hi,
recently I started working my way through this chapter. It's the most interesting part, but it's quite difficult to read (at least compared to the other parts and especially if your are quite new to Rust, like me and I guess most people here).

For instance, I guess it would increase the readability to use less Rust code in the section-headings and also in the text. This means less Rc<RefCell<Node>> in the continuous text (only in examples or if the words fit into the text, i.e. 'Weak pointer' is fine). Another issue is the choice of words: It could be more consistent with the official Rust documentation (which c++ programmers will definitely consult, too).
@nrc If you do not like these ideas, please let me know.

I would be happy to make some proposals and to contribute to this.
Just started a branch some days ago (work in progress): https://github.com/Liamsi/r4cppp/tree/reading_graphs_arena
I did not find the time to come up with good alternatives for every issue yet, but this issue is also a reminder to myself to do so.

Cheers and thanks again for this project ๐Ÿ‘

Do while loops

I think it is worth mentioning that do..while loops can be achieved by prepending the body of the loop to the condition

   let x=1;

   // while loop
   while {x == 0}{
        println!("This is not executed");
   } 

   // do while loop
   while {
        println!("This is executed");
        x == 0
   }{} 

Errors in borrowed chapter

In this chapter, the following code snippet will raise compile error

fn foo() {
    let mut x = 5;            // type: int
    {
        let y = &mut x;       // type: &mut int
        //x = 4;              // Error - x has been borrowed
        //println!("{}", x);  // Error - requires borrowing x
        let z = *y + x;       // Ok - doesn't require borrowing
    }
    x = 4;                    // OK - y no longer exists
}

Why would a reference dereference?

In Destructuring, you write

Lets say you want a reference to a variable in a pattern. You can't use & because that matches a reference, rather than creates one (and thus has the effect of dereferencing the object). For example, ...

  1. Do you mean a) "Let's say you want to make a reference to an (ordinary) struct field using a pattern (effectively aliasing the field)", b) "Let's say you want to refer to a reference variable in a struct using a pattern (creating an additional reference to the object referred to by the field)" or c) something else?

  2. Why would "matching a reference" have the effect of dereferencing the object? On the face of it, that is surprising behavior (unless it's to avoid a &&T (in which case I'd still have expected the dereference to yield the expected &T)). Maybe another sentence explaining why the dereference would be helpful?

Mention integer overflow/wrapping behavior

In the primitive type chapter, it might be a good idea to describe the mechanisms of integer overflow in Rust. (RFC 560) And also the difference between debug and release build here.

unused_mut warning in control-flow.md

This code:

fn foo(x: i32) -> &'static str {
    let mut result: &'static str;
    if x < 10 {
        result = "less than 10";
    } else {
        result = "10 or more";
    }
    return result;
}

Gives a warning that the mut on result is not used and recommends removing it. It made me play around with it and notice that rust is very smart about statically analyzing when things are initialized. I think it would have been a great time to mention that.

arena error

compile error
use arena::TypedArena;
|
3 | use arena::TypedArena;
| ^^^^^ use of undeclared type or module arena
lack of something?

Destructuring pt2 - confusion about temporary variables created in match statements

In Destructuring pt2, in the second code snippet, regarding the first option of the match statement, it says

"...in the first approach we dereference x to a temporary variable with type Enum1 (which copies the value in x)...".

Enum1 has copy semantics, so it makes sense that *x (the value in x) is copied into a temp variable. From that I conclude that if there is a match statement on a dereference of an object with copy semantics, a temporary variable is created and the value of *x is copied into it. So far so good.

However, in the third code snippet, option 1 of the match statement, where the value of x (now of type Enum2) has move semantics, shouldn't the same hold true, but this time, with a move operation, making this scenario illegal? That is, when creating a match statement on a dereference of an object with move semantics, it should, following the same logic, result in a temporary variable into which *x would be moved? Or does that not apply in case of object with move semantics? That is, if you have a match statements on a dereference of an object with move semantics, no temporary variable is created?

I don't know the answer as I'm just starting out with Rust and it gets me confused. I think this point should be clarified.

Error Handling

I would like to write a chapter on Rust's error handling and comparing and contrasting it against both integer/custom type error handling and exceptions in C++.

I just wanted to check to see if this would be worthwhile work before I started going too deep.

Bad code-section example

Hey! I'm a beginner, but something worked and on the guide it said it shouldn't have worked.

On the "Borrowing Pointers" section, we've been given this code section:

fn foo() {
    let mut x = 5;            // type: i32
    {
        let y = &mut x;       // type: &mut i32
        //x = 4;              // Error - x has been borrowed
        //println!("{}", x);  // Error - requires borrowing x
    }
    x = 4;                    // OK - y no longer exists
}

First, on lines x = 4 and println!... the comment is a direct contradiction.
Second, uncommenting the println! does work. I'm not sure what that means though, but
something here is unclear.

EDIT: This is also true when uncommenting x = 4. I'm not really sure about the validity of this example.

Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.