[HN Gopher] A half-hour to learn Rust
       ___________________________________________________________________
        
       A half-hour to learn Rust
        
       Author : selvan
       Score  : 1037 points
       Date   : 2021-01-02 05:50 UTC (17 hours ago)
        
 (HTM) web link (fasterthanli.me)
 (TXT) w3m dump (fasterthanli.me)
        
       | stonecharioteer wrote:
       | I spent a few hours typing this entire article into an editor
       | just to build muscle memory and I'm amazed. It's exactly the sort
       | of article I needed to learn Rust. I've since thanked Amos on
       | Twitter and I've forwarded links to his blog to a lot of people.
       | This is a great article and does a good job clarifying things to
       | a newcomer.
        
       | mlthoughts2018 wrote:
       | So Rust is Scala but with some extra complicated additional
       | syntax around borrowing references and generic lifetime
       | constraints.
        
         | steveklabnik wrote:
         | Scala has many features Rust does not have as well.
        
           | mlthoughts2018 wrote:
           | Yeah, when reading this I was wondering if Rust has sealed
           | traits like Scala, and also structural typing.
           | 
           | The extreme degree of shared syntax and shared semantics with
           | Scala was really surprising to me.
        
             | steveklabnik wrote:
             | Rust does not have sealed traits, though you can sorta
             | contort the privacy system to do similar things if you
             | want. We also do not have structural typing. (Generally;
             | tuples are structurally typed but nothing else is)
             | 
             | A lot of Rust's language people did a lot in Scala. The
             | language's are pretty different IMHO.
        
               | nobleach wrote:
               | As was explained to me, Rust has heritage from OCaml. If
               | one squints, they can even see it still beneath the
               | surface. I hear the original compiler was even written in
               | OCaml.
        
               | steveklabnik wrote:
               | Yes, especially amongst the earliest folks, there was a
               | lot of OCaml, and the original compiler was, yes.
        
         | sireat wrote:
         | Seeing Scala for the first time seemed this is what happens
         | when Java marries Python.
         | 
         | Rust seems like when C++ marries Scala.
         | 
         | Disclaimer: I like C, Python and Scala but not a big fan of C++
         | and Java
        
         | vips7L wrote:
         | Probably the reason why I don't like rust. Scala is hell for
         | me. I've been burned by it so many times.
        
       | blargmaster42_8 wrote:
       | Can't take anyone that uses
       | 
       | if(..){
       | 
       | Notation seriously.
        
       | moron4hire wrote:
       | Very nice. As a very experienced programmer who has now learned
       | more languages than I can remember, I generally look for these
       | kinds of cheatsheets whenever I'm learning a new language,
       | followed by the official documentation. Other than that, I don't
       | personally find tutorials very useful.
       | 
       | The cheatsheets give me a quick intro to syntax conventions, and
       | then the official documentation provides all the detail on
       | specifics. I'm looking to mentally map how different PL
       | constructs common across different languages are expressed in the
       | new language I'm learning.
       | 
       | Along the way, I end up learning one or two new PL concepts.
       | Fewer these days than in the beginning, hence it gets easier and
       | easier to learn new languages.
        
       | kliments wrote:
       | Thank you for this comprehensive article! Definitely reading and
       | saving it for future reference.
        
       | malwrar wrote:
       | This is precisely what I was looking for when I searched for
       | "Rust for C++ programmers" in the past. I love the Rust book, but
       | I've always thought the common focus on accessibility for newbie
       | programmers made it feel tedious for those who are more seasoned.
       | I'd love to see more writing like this, maybe even for other
       | things like libraries!
        
         | ufmace wrote:
         | I've found it's generally really tough to find guides for
         | getting into new languages that are written for experienced
         | programmers who don't know that language yet. Everything seems
         | to be written for complete newbies, or be a dense reference
         | that assumes you know almost everything already.
         | 
         | It's a bit annoying, but not much to do except slog through the
         | guides and try to write a few programs.
        
         | bluejekyll wrote:
         | I found the Rust book to be anything but tedious, as a seasoned
         | programmer. As I read it, it made me want to cry thinking back
         | on past bugs and issues that I had dealt with that the language
         | had been designed to prevent.
         | 
         | It made me think of the days and weeks of debugging that I
         | wouldn't have needed to do, had Rust existed.
        
         | pascalgn wrote:
         | If you already know C++, https://overexact.com/rust-for-
         | professionals/ might be for you (disclaimer: I wrote this)
        
           | morrbo wrote:
           | I prefer your guide if it is any consolation. Thanks for
           | writing it
        
       | vghaisas wrote:
       | In college, I wrote something sort of like this to help students
       | prepping for interviews in C++: https://vghaisas.com/code-
       | quickref/cpp.html
       | 
       | I quite like the format (though this post is much better than
       | mine) of lots of small snippets of code showing how something is
       | used.
        
       | hawski wrote:
       | It's a great resource. I like such easy list approach, because
       | many times new language just needs a translation from concepts
       | you already know.
       | 
       | I have a problem understanding how temporaries work in Rust. At
       | least from what I see there is a difference between a temporary
       | inside a vec that I bind somewhere to then pass it somewhere and
       | a temporary inside vec constructed inside method invocation. I
       | asked on SO [0], but did not receive satisfactory answer, or I'm
       | too dense to understand it.
       | 
       | [0] https://stackoverflow.com/questions/64705654/why-i-get-
       | tempo...
        
       | k1t wrote:
       | Incredible. Great job.
       | 
       | Oh, I guess it's a year old - but still, extremely good.
        
       | emerged wrote:
       | This seems good but it starts using borrow in a bunch of examples
       | without saying what it even is.
        
       | dimmuborgir wrote:
       | Previous discussion:
       | https://news.ycombinator.com/item?id=22448933
        
         | minimaxir wrote:
         | I suppose we can now put (2020) in submission titles. :P
        
           | gpvos wrote:
           | A grace period of about one to two months seems reasonable.
        
       | kaleidawave wrote:
       | Was initially sceptical to this but after skimming think this is
       | actually a very good introduction. I do like the brevity of it
       | compared to the walls of text in the official rust one. Although
       | this does give an illusion that Rust is very simple/easy to learn
       | but any beginner will find that anything more than "Hello World"
       | or "2 + 4" is 10x more difficult than writing in a interpreted
       | language. Not because Rust syntax is difficult but the
       | constraints it introduce require more thought of the design of
       | the program.
       | 
       | The article also skims over the single ownership model which is a
       | big difference with Rust. And it does miss about creating macros,
       | cells, threading & mutexes, heap allocated types, unsafe code,
       | Rc, std::mem, and the whole crates and cargo ecosystem. Which is
       | why I think this should have been titled "half-hour introduction
       | to Rust syntax". Hopefully this does bring more people on the
       | Rust train. I think 2021 will be a good year for Rust :)
        
         | fasterthanlime wrote:
         | Since a lot of folks take issue with the article's title, think
         | of it as "If you had only a half hour to learn Rust, here's
         | what I'd tell you".
         | 
         | If you have more, do engage in a joust^W friendly collaboration
         | with the compiler, which will get you quite far since
         | diagnostics are a first-class feature :)
        
       | jokethrowaway wrote:
       | This is great!
       | 
       | You probably want to add feeling_lucky: bool as an argument to
       | fair_dice_roll()
        
       | laydn wrote:
       | What I would like to also see in these types of well written
       | articles is the answer to questions like "what can you do with
       | Rust that you can not do with C?"
        
         | fasterthanlime wrote:
         | This may answer part of your question -- it's focused on
         | strings but draws parallels with C all along:
         | https://fasterthanli.me/articles/working-with-strings-in-rus...
        
         | pjmlp wrote:
         | Having to ask for permission to corrupt memory.
        
         | psanford wrote:
         | Write code that is memory safe.
        
         | cesarb wrote:
         | Most answers will focus on safety, but setting that aside,
         | there's one thing Rust has which AFAIK C doesn't have: fat
         | pointers. They're the implementation detail behind both array
         | slices (keeping together the pointer to the first element and
         | the length) and trait references (keeping together the pointer
         | to the object and the pointer to the vtable).
        
       | sanmak wrote:
       | Snippets looks quite impressive. But if it's segregated into
       | different post like https://flaviocopes.com/ did, then it'll be
       | much helpful.
        
       | mrlonglong wrote:
       | It only took me a couple of hours to port one of my old C
       | programs, an utility to produce a hexadecimal and ASCII dump to
       | Rust. The Borrow checker didn't even faze me. All I needed was
       | plenty of Google-fu and my coding skills. JetBrains CLion and git
       | are also very useful tools.
        
         | rualca wrote:
         | > It only took me a couple of hours to port one of my old C
         | programs, an utility to produce a hexadecimal and ASCII dump to
         | Rust.
         | 
         | Writing C code with Rust is a very different experience than
         | converting C code to idiomatic Rust. There is more to porting
         | than doing 1:1 conversions between keywords.
         | 
         | And by your description your utility basically reads words and
         | prints their value. That doesn't really venture too much beyond
         | the hello world territory.
        
           | mrlonglong wrote:
           | u8s, actually. But yes, you are right that was a very simple
           | port. I to plan to do a port that's more complicated soon.
        
         | chamakits wrote:
         | I had a similar experience porting a relatively straightforward
         | and simple CLI utility I had written in C.
         | 
         | Having said that, when I've faced real challenges with Rust
         | (and the borrow checker) it's been with bigger longer running
         | applications, like a webapp, or a long running service.
         | 
         | I have no doubt part of that comes I have a stronger background
         | in garbage collected languages, so my mindset when developing
         | larger applications is in that mode. I'm sure with enough
         | practice I'd get it, but there were many things that I just
         | couldn't replicate one to one in Rust. Not that they weren't
         | possible, but they were just different enough that I couldn't
         | figure it out without being more comfortable in understanding
         | the language, and I just haven't dedicated the time needed to
         | it.
         | 
         | Will likely go back to it at some point, as it is an
         | interesting approach to programming, with lots of upsides.
        
           | mrlonglong wrote:
           | My biggest issue was trying to print the contents of u8 as a
           | character. In the end this was actually as simple as writing
           | print!("{}", line[i] as char), no print specifiers needed.
           | 
           | I may do another more complicated port soon. I love CLion.
        
         | mikewarot wrote:
         | The first I'm hearing of the "borrow checker"... so I started
         | reading this https://blog.logrocket.com/introducing-the-rust-
         | borrow-check..., and I got to the part where it says
         | 
         | "Your programs have access to two kinds of memory where it can
         | store values: the stack and the heap."
         | 
         | They left out variables, which is odd.
        
           | coldtea wrote:
           | How are variables not in either the stack or the heap?
        
             | mikewarot wrote:
             | When you write a program, heap variables are allocated
             | using NEW or Malloc... stack variables are local to a
             | procedure or function, the rest are in the Var block before
             | your code, and are neither on the heap, nor the stack.
             | They're global to the program, or the unit.
        
               | coldtea wrote:
               | You mean global/static variables?
               | 
               | Yeah, those are not mentioned. It also doesn't mention
               | constant storage...
               | 
               | That said it's not like they're the bread and butter of
               | programming for their lack of mention to be that "odd" as
               | the parent implies.
        
               | Aeolun wrote:
               | Wouldn't that mean they're on the heap by default? Your
               | program will have to malloc _something_ if they don't go
               | on the stack.
               | 
               | (My low level knowledge is limited, may be completely
               | wrong)
        
               | coldtea wrote:
               | In some (interpreted mostly) languages they are. Like
               | some also don't have a stack at all.
               | 
               | But in the most common languages, there is special
               | storages for globals, statics, and constants, which is
               | what the grandparent means (e.g. the DATA section).
        
       | mcsalgado wrote:
       | In the 9th code snippet that's not an example of variable
       | shadowing, it's just variable reassignment. Shadowing involves
       | variable assignments in different scopes.
       | 
       | https://en.wikipedia.org/wiki/Variable_shadowing
       | 
       | edit: I should've called it "variable redefinition" or something
       | like that I guess, my mistake. Reassignment is definitely not the
       | correct terminology for this.
       | 
       | Still, it's not shadowing because the new binding of 'x' is not
       | effectively shadowing some other 'x' name, it's just taking its
       | place in the same scope. And this is orthogonal to the memory
       | allocation of the assigned objects.
        
         | stormbrew wrote:
         | There is effectively an implicit scope created by the let
         | binding. In rust you can't reassign a variable without it being
         | mut. The two `x`s are separate variables named x and are not at
         | any point mutated. Reassignment would look like this:
         | let x = 1;         x = x + 1; // <- error[E0384]: cannot assign
         | twice to immutable variable `x`         let mut x = 1;
         | x = x + 1; // ok!
         | 
         | This obviously matters very little for an integer, but it is
         | relevant to more complex types.
         | 
         | You can actually see the scopes, and the progress of variable
         | liveness, if you run the compiler out to the MIR intermediate
         | language:                   fn main() -> () {             let
         | mut _0: ();                      // return place in scope 0 at
         | src/main.rs:1:11: 1:11             let _1: i32;
         | // in scope 0 at src/main.rs:2:9: 2:10             scope 1 {
         | debug x => _1;                   // in scope 1 at
         | src/main.rs:2:9: 2:10                 let _2: i32;
         | // in scope 1 at src/main.rs:3:9: 3:10                 scope 2
         | {                     debug x => _2;               // in scope
         | 2 at src/main.rs:3:9: 3:10                 }             }
         | bb0: {                 StorageLive(_1);                 //
         | scope 0 at src/main.rs:2:9: 2:10                 _1 = const
         | 1_i32;                // scope 0 at src/main.rs:2:13: 2:14
         | StorageLive(_2);                 // scope 1 at src/main.rs:3:9:
         | 3:10                 _2 = const 2_i32;                // scope
         | 1 at src/main.rs:3:13: 3:18                 _0 = const ();
         | // scope 0 at src/main.rs:1:11: 4:2
         | StorageDead(_2);                 // scope 1 at src/main.rs:4:1:
         | 4:2                 StorageDead(_1);                 // scope 0
         | at src/main.rs:4:1: 4:2                 return;
         | // scope 0 at src/main.rs:4:2: 4:2             }         }
         | 
         | https://play.rust-lang.org/?version=stable&mode=debug&editio...
        
           | mcsalgado wrote:
           | Oh interesting, I see now! Thanks for clearing this up.
        
         | bysin wrote:
         | In the wikipedia entry you provided, there's an example in
         | Rust, similar to the 9th code snippet, that claims it is
         | variable shadowing:
         | 
         | https://en.wikipedia.org/wiki/Variable_shadowing#Rust
        
         | red2awn wrote:
         | There is literally a Rust example in your wiki link saying that
         | this is shadowing. You can even redefine the variable to have a
         | different type, how can this be reassignment.
        
         | kd5bjo wrote:
         | No, it really is shadowing. The second `let` allocates a new
         | memory location in the activation record; all future mentions
         | of the variable name will refer to the new location. The old
         | location still exists, and may have references to it already;
         | references that will continue pointing at the old allocation
         | and will not see anything that happens to the new one. If the
         | old value has a `Drop` implementation, it will run after the
         | second allocation's `drop()`. The two `let` bindings can even
         | have completely different types.
        
         | powersnail wrote:
         | Isn't variable reassignment a special case of variable
         | shadowing, where the new scope closes at the same place as the
         | parent scope?
        
         | psyklic wrote:
         | In Rust, shadowing is when you "declare a new variable with the
         | same name as a previous variable" [1] -- even in the same
         | scope. It seems it "fell out" of how the original compiler was
         | implemented, and there was more support to retain it than not.
         | See: https://internals.rust-lang.org/t/history-of-shadowing-in-
         | ru...
         | 
         | [1] The "Rust book" has a good explanation of shadowing, which
         | contains a nearly identical example. See: https://doc.rust-
         | lang.org/book/ch03-01-variables-and-mutabil...
        
       | aero-glide2 wrote:
       | I had no intention of learning Rust, but this title just made me
       | do that.
        
       | pddpro wrote:
       | Thank you so much for this. I wonder if similar guides exist for
       | languages like Go and Julia.
        
       | freedomben wrote:
       | Absolutely love the humor in this                   fn
       | fair_dice_roll() -> i32 {             4         }
       | 
       | :-D
        
         | cesarb wrote:
         | It's a xkcd reference. https://xkcd.com/221/ (xkcd: Random
         | Number)
        
       | wintorez wrote:
       | Another great resource: https://learnxinyminutes.com/
        
         | bamboleo wrote:
         | I'm surprised AngularJS is on there but React isn't.
        
           | golergka wrote:
           | They are open for PRs!
        
       | [deleted]
        
       | Aeolun wrote:
       | When I read these articles everything always seems so
       | understandable, but I can pretty much guarantee that I won't
       | remember much tomorrow.
        
         | axihack wrote:
         | Same with me, to learn anything I need to write it down,
         | possibly several times.
        
           | stonecharioteer wrote:
           | I recommend typing out the entire article as in into an
           | editor. After you work your way through it, try the rustling
           | course, Rust by Example, the CLI tutorial and then read The
           | Book.
        
           | pddpro wrote:
           | Have you tried Anki or similar Spaced Repetition System?
        
             | majewsky wrote:
             | SRS is really good for learning small, compartmentalized
             | knowledge items. Its usefulness degrades quickly when you
             | move from knowledge to concepts. I'm currently learning
             | Japanese and using several SRS tools to do so. The ones
             | that work the best are for characters and vocabulary. I
             | also use one for grammar, which is okay-ish but doesn't
             | translate as well to the SRS format.
             | 
             | So in the context of programming languages, SRS might work
             | if you need to memorize method names or method signatures
             | (though I don't see why that is needed in the age of
             | autocompletion and instant lookups from inside the text
             | editor), but not so much for fundamental language concepts
             | (like "how do lifetimes interact with the borrow checker").
        
       | nitred wrote:
       | As a Python programmer with limited experience with compiled
       | languages, Rust code was more intimidating to read or look at
       | than C++, Java or Go. After only an hour, I am overwhelmed by the
       | sheer beauty and mature design of this language - it almost reads
       | like Python or as well as any compiled language can. I cannot
       | believe that I am smitten by Rust within an hour. Its features
       | seem, obvious. My experience with Go was frustrating since I felt
       | like I had to give up elegance for practicality. I did not expect
       | to learn 1-2% of Rust when I woke up today. My thanks to the
       | author.
       | 
       | I'm curious what other what other developers who primarily use
       | Python think of this article and Rust in general?
        
         | christiansakai wrote:
         | Rust makes hard things easy and easy things hard.
         | 
         | Also reading Python code is easier (less syntax noise) on the
         | eyes. The article above is very beginner Rust, and I won't rely
         | on that to look at actual Rust code in the wild.
         | 
         | If you want to take a look at what actual Rust code in the
         | wild, take for example, a web server Actix, and try to figure
         | out what the documentation says.
        
           | felipellrocha wrote:
           | > Rust makes hard things easy and easy things hard.
           | 
           | I don't agree with this, and, if anything, this reads very
           | biased.
           | 
           | Insofar, Rust has made my life a lot easier, and I have not
           | run into any major issues aside the borrow checker. And this
           | was early on. Two years now playing with the language and I
           | barely run into it anymore.
        
             | christiansakai wrote:
             | Async has ecosystem fracture issues. Creating graph data
             | structures require you to understand more about borrow
             | checker.
             | 
             | Majority of people will probably want to use Rust for web?
             | Which makes async needs to be ergonomic enough if it wants
             | consider wide adoption.
        
               | dralley wrote:
               | So does Python. Asyncio is mediocre at best and difficult
               | to express certain patterns in. Other libraries are far
               | better, but not in the standard library.
        
           | simias wrote:
           | I find that advanced Python is quite hard to read. Well, I
           | find that advanced dynamically typed languages tend to be
           | hard to read in general, because you can never be sure what
           | type your inputs and outputs are and what values they can
           | take. Usually my
           | 
           | At least idiomatic Python shuns wildcard imports that
           | obfuscate where symbols are coming from (that drove me insane
           | in Ruby).
           | 
           | On the other hand Rust code tends to be very strict about
           | what your types are (even more so than a language like C++
           | where metaprogramming is duck-typed by default). It can lead
           | to complicated code, but baring some weird operator
           | overloading decision you should know exactly what calls what
           | from whom when you look at any method or function.
           | 
           | Rust code can be tricky to write at times, but I generally
           | find it a pleasure to read. Sure, ultra-complicated generic
           | code can be overwhelming, but this complexity would be here
           | in one form or the other regardless of the language, Rust
           | just forces you to be explicit about it.
        
           | cute_boi wrote:
           | "Rust makes hard things easy and easy things hard."
           | 
           | Disagree here. Like article Rust 2018 is very nice and
           | ergonomic. Iterators, Lifetime Elision etc are nice to work.
           | 
           | Regarding noise many people consider those noise but I find
           | noises like return types etc very useful. Because I can be
           | sure the return type. Regarding actual code actix doesn't
           | look that bad from examples also.
           | 
           | I use warp and its pleasant to work. The only thing I hate is
           | compilation time other than that I don't think I have any
           | major criticism against rust. But compilation time is near to
           | cpp etc so ...
        
             | christiansakai wrote:
             | Actual code examples from Actix isn't that bad but take a
             | look at the docs.
        
             | mikepurvis wrote:
             | I'm a recent Rust fan (via AoC), but for "easy things
             | hard", I would offer input/string processing as an
             | example-- regexes, string operations, grammar, etc. I
             | _know_ that Rust is forcing me to be correct and handle (or
             | explicitly acknowledge that I 'm not handling) my error
             | cases, but from the point of view of just wanting to get
             | the happy path working, it's a lot more noise to deal with
             | compared with what it would look like in Python, eg:
             | let re = Regex::new("(?P<min>[0-9]+)-(?P<max>[0-9]+)
             | (?P<letter>[a-z]): (?P<password>[a-z]*)").unwrap();
             | re.captures_iter(&contents).map(|caps|
             | Input {                     password:
             | caps.name("password").unwrap().as_str().to_string(),
             | letter: caps.name("letter").unwrap().as_str().chars().next(
             | ).unwrap(),                     min:
             | caps.name("min").unwrap().as_str().parse().unwrap(),
             | max: caps.name("max").unwrap().as_str().parse().unwrap()
             | }             ).collect()
        
               | projct wrote:
               | If you get rid of unwrap and use `if let` and `match`,
               | this code will clean up nicely.
               | 
               | If the code is supposed to be maintainable, you could
               | also make something like a FromRegex trait for Input. It
               | would be a good idea to try exercism's mentoring thing to
               | get better at writing it the easier way the first time.
               | The mentoring thing really is what helped me to think in
               | ways that made this mess easier to avoid.
        
         | artursapek wrote:
         | > I cannot believe that I am smitten by Rust within an hour
         | 
         | This has been my, and a lot of my colleagues', experience with
         | Rust. Never have I seen people fall in love with a programming
         | language so strongly. And the love lasts for a long time.
        
           | christiansakai wrote:
           | Try to use that in real world and see if your love still
           | stays put. An hour is not enough to validate Rust.
        
             | artursapek wrote:
             | Typical condescending HN response. We are using Rust, we've
             | used it to build and ship a successful native desktop app.
        
             | [deleted]
        
           | CRConrad wrote:
           | Do you know any Object Pascal programmers?
        
         | ithrow wrote:
         | _am overwhelmed by the sheer beauty and mature design of this
         | language - it almost reads like Python or as well as any
         | compiled language can._
         | 
         | All those lifetime annotations are not sheer beauty or pretty,
         | sure they are necessary but not nice to look at if you are
         | comparing it to a higher level language.
        
           | nitred wrote:
           | I agree it's not pretty. It took me several passes to just
           | understand what was going on there. But ownership is
           | something I've never come across before and it doesn't exist
           | in Python (not to an average user anyway), so it seems a
           | little unfair to compare Rust and Python based on that
           | feature.
           | 
           | However when you take a high level feature like overriding
           | operators which can be done elegantly in Python, for a
           | complied language, Rust's way is quite concise, readable and
           | to my eyes quite pretty.
           | 
           | Edit: Typos
        
           | globuous wrote:
           | Except from that though, it really looks like ocaml, which
           | really makes me want to look into rust a little bit more :)
        
             | fasterthanlime wrote:
             | Yup, strong similarities there, since the original Rust
             | compiler was implemented in OCaml :)
        
               | julenx wrote:
               | For those who are curious, here's the source code of the
               | original compiler written in OCaml (rustboot)
               | https://github.com/rust-
               | lang/rust/tree/ef75860a0a72f79f97216...
        
           | the_duke wrote:
           | You can write Rust code with almost no lifetine annotations.
           | That's heavily dependent on the domain, of course. But for
           | relatively simple function signatures they are usually
           | inferred correctly, and you can often just clone instead of
           | requiring references.
        
             | throwaway894345 wrote:
             | Pretty sure if you're deserializing a structure with
             | borrowed references you need lifetime annotations. Copying
             | things around to pacify the compiler hardly seems elegant.
        
               | the_duke wrote:
               | Sure, but that's a performance vs ease of use decision.
               | 
               | Often you don't need to care about the extra allocations
               | and can just deserialize to owned types.
               | 
               | The code for owned deserialization certainly ends up
               | looking more elegant.
        
               | throwaway894345 wrote:
               | It's not just performance, but you now have to go back
               | and update every instance of that struct to reflect the
               | change in ownership of that member if you can even change
               | the member in the first place (e.g., you can't change the
               | type of a member of the struct itself is defined in a
               | third-party package). Moreover, some instances of your
               | struct might be in a tight loop and others might not, but
               | now you're committing to poorer performance in all cases.
               | Maybe you can box it (although IIRC I've run into other
               | issues when I tried this) but in any case this isn't the
               | "elegance" I was promised. Which is fine, because Rust is
               | a living, rapidly-improving language, but let's not
               | pretend that there is an elegant solution today.
        
             | nobleach wrote:
             | Yes, you can clone all day long and just reuse variable
             | names as if you were writing JavaScript, but what does that
             | do to your memory allocation?
        
               | throwaway894345 wrote:
               | To be clear, JS doesn't require cloning because it has a
               | gc. Not sure what you're getting at with reusing
               | variables names...
        
               | nobleach wrote:
               | What I mean is, if one does:                 const obj1 =
               | { a: 32, b: 42 };       function foo(ref) { ref.a = 0; }
               | foo(obj1);       console.log(obj1);
               | 
               | in JavaScript, one is just using the variable name as a
               | "holder" of some value. One doesn't have to designate
               | that that variable is being passed by reference. If one
               | wanted to actually copy that object, they'd have to
               | devise a mechanism to do so. In Rust, if someone doesn't
               | specify, using the & symbol, that something is a
               | reference, it'll end up moving the value.
               | 
               | Basically all I was saying is one can not approach
               | writing Rust with a Java/JavaScript mindset. (That a
               | variable is just a bucket holding a value). Care needs to
               | be taken when referencing a variable as it may need to be
               | moved, copied/cloned or referenced. In the case of
               | copying, another memory allocation is done. So if someone
               | approaches Rust from the standpoint of "this word
               | represents a value, and I'm going to use it all over the
               | place", they can find themselves blindly allocating
               | memory.
        
               | throwaway894345 wrote:
               | Oh, by "reuse variable names", you simply mean that
               | values aren't moved, i.e., that JS lacks move semantics
               | or an affine type system. That's a bit different to
               | "reusing variable names", which you can do in Rust as
               | well provided the variable holds a (certain kind of?)
               | reference.
        
               | gpm wrote:
               | _Most_ languages just clone all day long, it 's not that
               | bad, rust clones (like most languages) are just to the
               | first reference counted pointer after all.
        
               | the_duke wrote:
               | Well, yes and no.
               | 
               | Eg cloning a string leads to an extra allocation and a
               | memcopy.
               | 
               | If you want to get a similar performance profile to GC
               | languages, you have to stick your types behind a
               | `Rc<T>>/Arc<T>` or `Rc<RefCell<T>> / Arc<Mutex<T>>` if
               | you need mutability.
               | 
               | But modern allocators hold up pretty well to a GC, which
               | amortizes the allocations. The extra memcopying can be
               | less detrimental than one might think.
        
               | throwaway894345 wrote:
               | "Yes and no" is too generous; most languages clone only
               | very infrequently (basically only for primitives where
               | there is no distinction between a deep and shallow copy).
               | For complex types (objects and maps and lists) they pass
               | references (sometimes "fat" references, but nevertheless,
               | not a clone).
        
           | volta87 wrote:
           | I think that being able to write down the lifetimes in the
           | language is beautiful.
           | 
           | You don't have to do it, but if you want to do it, being able
           | to do so in a way that's verified and enforced by the
           | toolchain beats doing so in a documentation comment.
           | 
           | Now every time I read a doc string saying that I need to
           | "deepcopy" something in Python for some API usage pattern to
           | work properly I cringe.
        
             | fasterthanlime wrote:
             | That's one of the things that get me about Rust discourse:
             | it seems that "Rust is pain in exchange for performance" is
             | a common misconception. Rust is discipline in exchange for
             | performance _and correctness_. A GC lets you be relatively
             | worry-free as far as memory leaks go (and even then..) but
             | it doesn 't prevent a lot of the correctness problems the
             | borrow checker would.
             | 
             | With a checker you're forced to think: do I really want to
             | pass a copy/clone of this? Or do I want to let that
             | function borrow it? Or borrow it mutably?
        
               | harikb wrote:
               | While I get the point about data-races, a "GC" doesn't
               | make/help you leak memory - you have simply postponed the
               | free to a later point in time.
               | 
               | Assume you had some code that takes a file name and calls
               | open on it. One day you decide you want to print that
               | filename before you open it. Naive code will cause the
               | name to "move" to print and unusable to the open in next
               | line. Even though it is perfectly understood by all
               | parties that there is no threading involved and print
               | would finish before the next use of that string. Yes, I
               | can create a borrow or clone, but having to think of it
               | every single line of code even when there is only one
               | thread of execution is really painful
               | 
               | Edit: I get print is a macro, but imagine a detailed
               | logger for this case.
        
               | fasterthanlime wrote:
               | I'd argue the exact opposite. Languages that _don 't_
               | have a concept of ownership, and a borrow checker, and
               | don't explicitly say if they want ownership, a reference,
               | or a mutable reference, force you to keep all of these
               | details in your head.
               | 
               | Here, if I have a `&T` and I try to call a function that
               | has a `&mut T`, the compiler will tell me that's not
               | gonna work - and then I can pick whether I want _my_
               | function to take a ` &mut T`, or if I want to make a
               | clone and modify _that_ , etc.
               | 
               | There's a learning curve, it's a set of habits to adopt,
               | but once you embrace it it's really hard to go back to
               | languages that don't have it! (See the rest of the
               | comments for testimonials)
        
               | millstone wrote:
               | I think both points are right. There's times when it's
               | useful and desirable to be specific about lifetimes, and
               | there's also times where it's annoying noise.
               | 
               | Bignum arithmetic is an example of the latter. You want
               | to just work with numbers, and in Python you can, but in
               | Rust you must clutter your code with lifetimes and
               | borrows and clones.
               | 
               | Swift's plan to allow gradual, opt-in lifetime
               | annotations seems really interesting, if it works.
        
               | CDSlice wrote:
               | Bignum arithmetic actually is pretty simple in Rust if
               | you use the right library. Rug[0] makes using bignums
               | look almost just like using native numbers through
               | operator overloading.
               | 
               | [0] https://crates.io/crates/rug
        
               | millstone wrote:
               | The operator overloading is nice but you still get
               | smacked in the face right away by the borrow checker.
               | Simple stuff like this won't compile ("use of moved
               | value"):                   let a = Integer::from(10);
               | let b = a + a;
        
           | rapsey wrote:
           | All those? Very small amounts of an average Rust code base
           | will have lifetimes.
        
           | felipellrocha wrote:
           | You get used to it, and you don't really need to use it most
           | of the time. Only for more complicated things, but by that
           | point, it's second nature.
        
         | thisisusername wrote:
         | As another Python programmer I also agree. Rust's features are
         | very mature especially compared to an old dinosaur like C. I
         | only wish its syntax was more like Swift's which is more
         | pleasing to the eyes and was also made by the same guy.
        
           | dagmx wrote:
           | Minor note,. Graydon created rust and worked on Swift. He
           | didn't create Swift however.
           | 
           | That said...both languages read like close siblings to me to
           | the point I find it annoying switching between the two
           | because I keep trying to use each ones language semantics in
           | the other subconsciously.
        
             | thisisusername wrote:
             | I feel like I'm being bullied and nitpicked but you're
             | speaking politely so I'm confused.
        
               | [deleted]
        
             | thisisusername wrote:
             | Stop narcissistically using peer pressure to turn people
             | against me. It's really gross and creepy and I will not
             | tolerate it.
             | 
             | Why am I flagged for standing up for myself like a good
             | person should?
        
         | bccdee wrote:
         | I was mostly a Python user, and now I primarily write Rust when
         | I can. It's an absolutely gorgeous language, especially for
         | being so practical.
         | 
         | There's a bit of a progression with Rust, where at first you
         | see the examples and you go "this language is so beautiful!"
         | Then you try to write something nontrivial in Rust and you go
         | "wow the compiler will NOT stop yelling at me, how does anyone
         | write anything in this language?" Rust has a fairly austere
         | learning curve in general, and it takes some getting used to.
         | 
         | That passes, though, and then you really do get to experience
         | the elegance and power which sold you on Rust in the first
         | place. There's a period where writing Rust feels substantially
         | slower that writing in anything else, but that passes too.
         | 
         | It really is as good as it sounds, but it might take a while
         | before you're accustomed enough to Rust's paradigm that it
         | feels that way.
        
         | mikeschmatz wrote:
         | Rust is a complete pain for the types of problems Python is
         | used for. Same for Go/Java.
        
           | dmit wrote:
           | I used to use Ruby for small (100-500 loc) scripts to parse
           | various CSV/JSON documents. You craft a couple perfect
           | stanzas of immaculate code to do what you need and you feel
           | great. Then you run it and turns out you forgot an `end`
           | somewhere. Fuck. You run it again, and the name of the hash
           | map variable is unknown, because you changed it at the last
           | moment to make it more descriptive. Fuck. There, fixed
           | everything. Run it again. Running for a couple seconds now
           | with no errors -- pop the champagne! Wait, what's that? Row
           | #998 of 1000 had an unexpected type of value? Fuck. Fix it,
           | ship it. Wheel, snipe, and celly.
           | 
           | At some point I just started writing these things in Rust
           | instead. Describe what I want deserialized as a struct. List
           | the fields I want as enum variants. What's that, rustc, the
           | "name" field is optional? Ok, that makes sense, I'll handle
           | this right away. Done. Hey, rustc, how come people talk about
           | fighting you all the time when you're actually the world's
           | greatest pair programmer?
        
         | zem wrote:
         | D is also worth a look as a compiled C- family language that
         | can read like python. https://bitbashing.io/2015/01/26/d-is-
         | like-native-python.htm...
        
         | bitL wrote:
         | Look into C++17, that one makes C++ look like Python but with
         | worse basic libraries (not that Python ones are great either).
        
           | rapsey wrote:
           | Unfortunately one can't live solely in C++17. The sheer
           | amount of syntax and knowledge required to write C++
           | productively is insane.
        
         | eeZah7Ux wrote:
         | > I am overwhelmed by the sheer beauty and mature design of
         | this language - it almost reads like Python
         | 
         | Sarcasm?
        
           | nitred wrote:
           | _"... or as well as any compiled language can. "_
           | 
           | Some syntax is close to Python so some mental load is
           | minimized, i.e use of _snake_case_ , _self_ , _None_ and type
           | annotation syntax, dict unpacking.
           | 
           | Some lines read like sentences i.e. for loops, single line if
           | statements, _impl Foo for Bar_ etc. Some design choices also
           | read better I think, for example, _let_ reads better than
           | _var_.
           | 
           | Of course such preferences are personal. I've read other
           | comments that mention that the tutorial covers only basic
           | Rust features and it can get much more complicated when using
           | more advanced features.
           | 
           | Edit: Added sentence about advanced features.
        
         | faitswulff wrote:
         | This podcast might be relevant: the creator of Flask who is now
         | using Rust: https://realpython.com/podcasts/rpp/18/
         | 
         | Edit - actually I was probably thinking of this podcast with
         | the same interviewee: https://rustacean-
         | station.org/episode/004-rust-in-production...
        
           | nitred wrote:
           | Just started listenting to it. It's exactly what I was
           | looking for, thank you. Armin Ronacher's opinion on such
           | things would hold a lot weight in my head.
        
         | jgraham wrote:
         | I've shipped relatively lots of code in Python and a little bit
         | in Rust.
         | 
         | For any project where performance or correctness are
         | significant concerns I'd much rather use Rust than Python. It
         | provides a lot more tools to help you write correct code, and
         | express invariants in a machine-checkable way. This means that
         | they are maintained when the code changes, even when multiple
         | contributors are involved. I'm must more confident in my
         | ability to ship correct code in Rust and maintain that
         | correctness over time.
         | 
         | Rust also doesn't have the performance ceiling (floor?) of
         | Python, either for single threaded programs, or -- especially
         | -- for those that benefit from concurrency or parallelism. Of
         | course for some progames there's a clear hot loop that you
         | could implement as a native extension in Python, but other
         | workloads have relatively flat profiles where the performance
         | bottlenecks are making allocations or similar.
         | 
         | As well as the actual language features, the commitment to
         | backward compatibility from the Rust authors means that you
         | don't get regular breakage simply from updating to a newer
         | version of the language. I think Python 2 being 2.7 for such a
         | long time gave people a false impression of how stable a
         | foundation Python provides and the fact that point releases of
         | 3.x often cause problems feels like it causes a lot of
         | unnecessary makework for Pyton users and is rather offputting.
         | 
         | That doesn't mean I'd always choose Rust of course. You do
         | require more upfront design to get something that works at all.
         | Some projects also benefit greatly from not requiring a compile
         | step and making use of the ubiquity of a Python interpreter.
         | And I think I'd find it difficult to justify using Rust for a
         | typical web backend that's mostly composing together various
         | well-tested libraries to provide an API on top of a database.
        
           | unethical_ban wrote:
           | My only bone to pick with this commentary is that it is 2020
           | and people are still complaining about Python as being
           | unstable because of 2 -> 3.
           | 
           | It was a rough transition, to be sure. Python2 was released
           | 20 years ago, and Python3 12 years ago. It is a pretty stable
           | language.
        
             | duckerude wrote:
             | It's specifically complaining about point releases of 3.x,
             | it only mentions 2 in an unrelated way.
             | 
             | The fix for https://bugs.python.org/issue40870 caused me
             | some grief when upgrading from 3.8.3 to 3.8.4 (though to be
             | fair, the ast module has different stability guarantees).
        
             | johnmaguire2013 wrote:
             | I don't think the parent is talking about Python 2 -> 3. I
             | think they are pointing out that for many developers,
             | moving to Python 3 happened very late. That means they ran
             | 2.7 since 2010 (roughly 10 years now.) Now that they are on
             | 3.x, they get issues with each new 3.x release.
             | 
             | The argument is that being on 2.7 for so long gave a false
             | impression of the language being more stable than it is -
             | developers just weren't using new versions.
        
             | gpm wrote:
             | My housemate was just rolling back from python 3.8 to 3.7
             | yesterday due to a backwards incompatible change breaking a
             | library... it's not just 2 -> 3 that makes python
             | relatively unstable compared to rust.
        
               | alexanderdmitri wrote:
               | What the issue?
        
       | wokwokwok wrote:
       | > There is a special lifetime, named 'static, which is valid for
       | the entire program's lifetime.
       | 
       | I've heard this many times before, but as the guide[1] says:
       | 
       | "You might encounter it in two situations... Both are related but
       | subtly different and this is a common source for confusion when
       | learning Rust."
       | 
       | 'static means _different things_ for references and trait
       | objects.
       | 
       | ie.
       | 
       | 'a: 'static --> reference with lifetime 'a lives forever and can
       | never be dropped.
       | 
       | T: 'static --> Type T has no references in it; it is effectively
       | 'entirely owned' by the owner of an instance of T.
       | 
       | These are totally different things with the same name.
       | 
       | (I believe technically there are actually three; `<T: 'static >`
       | is a type constraint and `T + 'static` is a trait bound, but that
       | both mean the same thing as far as I know)
       | 
       | [1] - https://doc.rust-lang.org/rust-by-
       | example/scope/lifetime/sta...
        
         | pornel wrote:
         | The missing information here is that lifetimes _don 't apply at
         | all_ to types that don't contain any borrowed references (such
         | as `i32`, or self-contained `String`).
         | 
         | So `T: 'static` doesn't require types to live for the entire
         | duration of the program. It requires borrows _if there are any_
         | to be valid for that long. If there are no borrows involved,
         | then  'static is ignored.
         | 
         | In practice `T: 'static` should be understood as "all temporary
         | references are forbidden here".
        
         | m-ou-se wrote:
         | `T: 'a` means that you _may_ keep values of type T around for
         | lifetime  'a, but not that they _will_. So `T:  'static` means
         | that you may keep values of that type around forever, as they
         | do not refer to anything that doesn't live forever.
         | 
         | So neither `&'a i32` nor `MutexGuard<'a, i32>` are 'static
         | (unless 'a is), because you shouldn't keep references like that
         | around longer than the stuff it points to. But i32 by itself
         | satisfies i32: 'static, because it's perfectly fine to keep an
         | i32 around forever. (But that doesn't mean that every i32 will
         | stick around forever.)
        
         | GolDDranks wrote:
         | The wording that "'static means different things" is a bit
         | misleading. It means the same thing, but the meaning different
         | because of the context:
         | 
         | Lifetime: lifetime means that the first lifetime outlives (is
         | as long or longer) the second
         | 
         | Type: lifetime means that the type is constrained by the
         | lifetime. Because 'static means "the lifetime of the whole
         | process". That means that the type is not constrained.
        
           | wokwokwok wrote:
           | I find it very confusing.
           | 
           | T: 'a is T outlives 'a; but types are not generated at
           | runtime.
           | 
           | All types are static; which is to say they are created at
           | compile time and exist for the lifetime of the program.
           | 
           | Or does rust generate type variants on the fly at runtime?
           | 
           | I didn't think it did...
           | 
           | It is a _constraint_ applied to arguments at _compile
           | time_... but r, that's what I thought anyway.
        
             | dbaupp wrote:
             | A type constraint like T: 'a or T: Trait is constraining
             | values of type T, not the type T itself. That is T: 'a is
             | saying "all references in values of type T live at least as
             | long as 'a". This includes 'a = 'static and the vacuous
             | case of T containing no references.
        
             | DougBTX wrote:
             | > T: 'a is T outlives 'a; but types are not generated at
             | runtime.
             | 
             | Yes, that's true, but you can make it a bit more specific
             | by saying "all the references in T outlive 'a". Then it
             | should make more sense, as references are generated at
             | runtime.
             | 
             | This gets to the heart of what makes Rust an interesting
             | language, as references are generated at runtime, but how
             | long those references are valid for is checked at compile
             | time using lifetime bounds.
        
             | kaoD wrote:
             | Types are not generated at runtime, lifetimes _are_ types
             | (although they cannot be constructed).
             | 
             | T<'a> and T<'b> are different types altogether (although,
             | being generic, they can resolve to the same type if 'a ==
             | 'b, but it's not required). All this happens at compile
             | time.
             | 
             | When you say T: 'a you say that T is a subtype of 'a hence
             | it lives longer.
             | 
             | https://doc.rust-lang.org/nomicon/subtyping.html
             | 
             | Maybe you're being confused by misconception 1 here?
             | 
             | https://github.com/pretzelhammer/rust-
             | blog/blob/master/posts...
             | 
             | Type T, being generic, can be an OwnedStruct, but also an
             | &'a BorrowedStruct or a StructWithReferences<'a>. The owned
             | one is a subtype of 'static since it's owned, but the ones
             | with lifetimes are subtypes of 'a which itself (being a
             | generic lifetime) can be a subtype of 'static or any other
             | lifetime. Again, all this happens and is checked at compile
             | time. This ensures that at runtime, the actual references
             | are alive as per their lifetimes without explicitly
             | checking them anymore.
        
               | wokwokwok wrote:
               | You misunderstand; what confuses me is how 'static can
               | mean the _same thing_ in both of these contexts.
               | 
               | T: 'static does _not mean_ the references in T must exist
               | for the lifetime of the application.
               | 
               | Ie. the lifetime constraint on T isn't the same 'static
               | from &'static where the reference must life for the
               | entire lifetime of the application.
               | 
               | Types are static. T: 'static applies to instances at
               | runtime.
               | 
               | These instances do not have and are not related to the
               | 'static lifetime which is "the entire length of the
               | application".
               | 
               | I accept:
               | 
               | > Type: lifetime means that the type is constrained by
               | the lifetime.
               | 
               | I don't accept the explanation:
               | 
               | > Because 'static means "the lifetime of the whole
               | process". That means that the type is not constrained.
               | 
               | A does not follow from B.
               | 
               | If you want something to mean "A type cannot have
               | references in it" then invent a 'noref lifetime.
               | 
               | 'static in this context would mean that all members of T
               | must be 'static, which means that _all instances of T
               | must be 'static_.
               | 
               | It does not mean that.
               | 
               | I don't understand why they have the same name; they are
               | not the same thing; it is an example of failure to have
               | orthogonality in the language design in my opinion.
        
               | AsyncAwait wrote:
               | > T: 'static does not mean the references in T must exist
               | for the lifetime of the application.
               | 
               | It means that T does not have non static references, so
               | it is not a requirement that it lives for the lifetime of
               | the application but can do so.
        
               | GolDDranks wrote:
               | You seem to misunderstand what type : lifetime means.
               | 
               | > 'static in this context would mean that all members of
               | T must be 'static, which means that all instances of T
               | must be 'static.
               | 
               | Your "which means that" isn't true. It doesn't mean that.
               | The syntax type : lifetime indicates that the values of
               | the type MUST BE ABLE to outlive the lifetime. It doesn't
               | mean that they NEED to outlive the lifetime.
               | 
               | This means, for example, i32 : 'static even in the case
               | doesn't live the whole 'static lifetime. It COULD live,
               | though, if the author of the code allocated it
               | statically.
        
               | kaoD wrote:
               | Sorry, I probably edited my comment while you were
               | replying and added a couple links.
               | 
               | Check misconception 2 here, I think it addresses your
               | point.
               | 
               | https://github.com/pretzelhammer/rust-
               | blog/blob/master/posts...
               | 
               | EDIT to your edit:
               | 
               | > 'static in this context would mean that all instances
               | of T must be 'static.
               | 
               | You mean in T: 'static?
               | 
               | No. It means that any instance passed as type T must be
               | bound by 'static and therefore could be held up to the
               | end of 'static. This does not mean that they're allocated
               | at compile time, it just so happens that static variables
               | (allocated at compile time) are 'static but the causality
               | is reversed.
               | 
               | > If you want something to mean "A type cannot have
               | references in it" then invent a 'noref lifetime.
               | 
               | It _can_ have references in it! As long as they 're bound
               | by 'static.
               | 
               | Here's an example: https://play.rust-
               | lang.org/?version=stable&mode=debug&editio...
        
               | [deleted]
        
               | wokwokwok wrote:
               | Oh, I've read that.
               | 
               | I just maintain that the word 'static is being overloaded
               | here to mean multiple different things.
               | 
               | 'static is not the "lifetime of the entire application"
               | when it is used in the context of T: 'static.
               | 
               | > It can have references in it! As long as they're bound
               | by 'static.
               | 
               | :)
               | 
               | ...but it can also have values in it which are not
               | 'static.
               | 
               | So is T: 'static, or not?
               | 
               | It's arbitrary semantics; ...but my take on it is:
               | 
               | - IF you take "x is 'static" as meaning the "X is valid
               | for entire lifetime of the application"
               | 
               | then if:
               | 
               | - x: &'static 'is static' and must be valid for the
               | entire lifetime of the application.
               | 
               | I would expect:
               | 
               | - x: T + 'static 'is static' and must be valid for the
               | entire lifetime of the application.
               | 
               | I'm happy to agree that's not what it _does_ mean, what I
               | 'm saying is that it is _inconsistent_ for it not to mean
               | that.
        
               | AsyncAwait wrote:
               | > ...but it can also have values in it which are not
               | 'static.
               | 
               | I don't think that's right. It can only have references
               | which live at least as long as 'static does (or longer,
               | but 'static is the longest so...)
        
               | kaoD wrote:
               | I think he means owned values (notice he didn't say
               | "other references") But actually... owned values are
               | bound by 'static!
        
               | kaoD wrote:
               | > 'static is not the "lifetime of the entire application"
               | when it is used in the context of T: 'static.
               | 
               | Yes it is.
               | 
               | T: 'static means T can live _up to_ the end of the
               | "lifetime of the entire application".
               | 
               | > ...but it can also have values in it which are not
               | 'static.
               | 
               | I don't follow. Values are indeed bound by 'static. If
               | they weren't we wouldn't be able to pass values to other
               | threads (which can potentially last as long as our
               | application's main thread).
               | 
               | > 'static is not the "lifetime of the entire application"
               | when it is used in the context of T: 'static.
               | 
               | It is. Any owned instance without non-'static references
               | inside can live up to the "lifetime of the entire
               | application". You might drop them earlier if you wanted
               | to, but you don't _have to_ since it can live up to the
               | "lifetime of the entire application" and therefore can be
               | passed for example into a thread that can hold the value
               | up to the end of the "lifetime of the entire
               | application".
               | 
               | Any owned value can be held indefinitely as long as the
               | program is running.
               | 
               | I'm taking a guess here: you mean that values' lifetimes
               | can be constrained (I guess you mean by dropping the
               | actual value). But it's the owner the one that ended it
               | earlier, not the caller (where 'static applied). You will
               | never be able to have an owned value with a lifetime
               | shorter than 'static without dropping it and, if you drop
               | it, you cannot pass it anywhere. Hence why any owned type
               | that is passed is, by definition, bound by 'static.
               | 
               | > ...but my take on it is:
               | 
               | > - IF you take "x is 'static" as meaning the "X is valid
               | for entire lifetime of the application"
               | 
               | > then if:
               | 
               | > - x: &'static 'is static' and must be valid for the
               | entire lifetime of the application.
               | 
               | > I would expect:
               | 
               | > - x: T + 'static 'is static' and must be valid for the
               | entire lifetime of the application.
               | 
               | Your expectations are correct and that's what it is. Just
               | replace "must be valid" with "can live up to".
               | 
               | That's why you need to pass T: 'static to threads,
               | because a separate thread needs something to hold up to
               | the end of the application since a thread can potentially
               | never end.
               | 
               | https://doc.rust-lang.org/std/thread/fn.spawn.html
        
               | wokwokwok wrote:
               | Fair I guess; we're just arguing semantics. The point I
               | was originally making is that:
               | 
               | 'a: 'static is read "'a outlives 'static" [1]
               | 
               | T: 'static is read "T is bounded by 'static" (apparently,
               | although I can't find a reference to it).
               | 
               | The syntax is the same, the meaning is different.
               | 
               | Maybe the 'static part of these two things _is_ the same,
               | but they seem to me to:
               | 
               | - mean different things
               | 
               | - use the same syntax
               | 
               | It is what it is I guess... just confusing as to why it
               | was decided to use _the same_ syntax for these things,
               | instead of something different.
               | 
               | You could argue that adding new syntax makes the language
               | more complicated; but I'm not sure. Does it make it less
               | complicated when you overload the same syntax with
               | multiple different contextual meanings?
               | 
               | Opinions probably vary.
               | 
               | [1] - https://doc.rust-lang.org/reference/trait-
               | bounds.html#lifeti...
        
               | [deleted]
        
               | kaoD wrote:
               | What confuses me is... why do you think the meaning is
               | different? There is no meaning overload. It's a single
               | meaning.
               | 
               | T: 'static would happily typecheck with &'a str if 'a:
               | 'static.
               | 
               | T: 'static typechecks:
               | 
               | - OwnedValue
               | 
               | - OwnedValueWithReferences<'a> where 'a: 'static
               | 
               | - &'a ReferencedValue where 'a: 'static /// &'static
               | ReferencedValue
               | 
               | - Foo<&'a Bar> where 'a: 'static /// Foo<&'static Bar>
               | 
               | ...and more.
               | 
               | See the example here: https://play.rust-
               | lang.org/?version=stable&mode=debug&editio...
               | 
               | Notice how bar2 has a &'a str where 'a: 'static and it
               | can be happily passed to bar.
               | 
               | Of course in T: 'static you're subtyping a type and in
               | 'a: 'static you're subtyping a lifetime (which implicitly
               | subtypes the type that it's applied on)... but the ":
               | 'static" part means exactly the same: "the left part of
               | this bound can live up to the end of the application".
               | Whether it's a lifetime, a borrowed type or an owned type
               | does not matter.
               | 
               | > It is what it is I guess... just confusing as to why it
               | was decided to use the same syntax for these things,
               | instead of something different.
               | 
               | Because they are the same.
               | 
               | We could of course separate them into 'noref,
               | 'yesrefbutstatic, 'staticref, etc. But then we'd have a
               | needlessly restrictive std:.thread::spawn that would
               | accept only Owned, or only Owned<'static> or only
               | &'static Referenced. The implications are the same, hence
               | they're the same. We wouldn't gain anything and we'd be
               | needlessly restricted.
               | 
               | A simpler way to put it: owned values have an implicit
               | 'static lifetime.
        
               | wokwokwok wrote:
               | What you say makes sense... but I struggle to reconcile
               | it with reality.
               | 
               | If "the left part of this bound can live up to the end of
               | the application" then why is &a not 'a where 'a: 'static?
               | a can live up to the end of the application. &a can live
               | up to the end of the application.
               | 
               | Why is the result "argument requires that `a` is borrowed
               | for `'static`"                   fn foo<'a: 'static>(a:
               | &'a str) { println!("{}", a) }         pub fn main() {
               | let a = "hello world".to_string();           foo(&a);
               | }
               | 
               | So I guess I'm going to have to just agree to disagree on
               | this one and bow out of this conversation thread I'm
               | afraid.
               | 
               | [1] -- https://play.rust-
               | lang.org/?version=stable&mode=debug&editio...
        
               | kaoD wrote:
               | What?
               | 
               | If you do 'a: 'static, then you just said 'a is at least
               | as long as 'static.
               | 
               | When you borrow the String, you just created a lifetime
               | that is not as long as 'static. Variables are dropped
               | (and hence unborrowed) in reverse order. So 'a will
               | necessarily be dropped before its owner, hence it's
               | shorter than 'static.
               | 
               | As you can see it complains that it's dropped at the end
               | of main() even though it should be borrowed for 'static.
               | If this was an owned value it would NOT be dropped at
               | main() since it would be moved into the function on call.
               | 
               | Nothing surprising here.
               | 
               | > &a can live up to the end of the application
               | 
               | Nope. Imagine spawning a thread and passing &a but
               | keeping 'a' in your main thread.
               | 
               | > bow out of this conversation thread I'm afraid
               | 
               | Welp I did what I could.
        
               | GolDDranks wrote:
               | > a can live up to the end of the application. &a can
               | live up to the end of the application.
               | 
               | Nope, a reference to a stack frame can't live up to the
               | end of the application. The stack frame gets deallocated
               | and the referent ceases to exist; therefore the reference
               | you're creating in your linked example doesn't outlive
               | 'static. `main` is not an exception to this in Rust.
        
         | DougBTX wrote:
         | > These are totally different things with the same name.
         | 
         | Another way to think about it is that "T: 'static" restricts
         | all references in T to be static, in the same way that "'a:
         | 'static" restricts 'a to 'static. The case when T doesn't
         | contain any references is then just a boring base case.
        
       | mikewarot wrote:
       | I was a complete Nube an hour ago... I understand info from Nubes
       | has special value, so I'll be as explicit as I can.
       | 
       | I must be slow, being an old fart... I've been at it for 53
       | minutes and got about 1/2 way before all the questions in my
       | brain stacked up to "full".
       | 
       | I'd add a recommendation at the top of this to have a Rust
       | compiler handy.
       | 
       | {} were called braces when I learned programming, [] were
       | brackets... this tripped me up, Unicode calls these {} curly
       | brackets ?!? (Why did it trip me up? Because on my screen in non-
       | dark mode, { and [ look identical due to my eyesight, and I
       | assumed I was looking at [ because the text said that's what it
       | was... as you get older, you'll understand)
       | 
       | I don't understand why b=a; c=a; <-- doesn't work because a is
       | "used up"???
       | 
       | I'll get a Rust compiler and start again.
       | 
       | I'm allergic to "macros" as they have had a special place in hell
       | because of their misuse in C... I hope Rust is more sane.
        
         | aliceryhl wrote:
         | Regarding a getting used up, the Rust compiler enforces a
         | single-ownership principle where all values must have a single
         | owner. If you move ownership of a to b, you cannot use a
         | anymore as it no longer has ownership of the value.
         | 
         | The only exception to the above is if a type "is Copy". This
         | means that values of this type can be copied very cheaply, and
         | in this case the compiler will allow you to use it multiple
         | times, which is implemented by it being duplicated on each use.
         | 
         | As for macros, they are nothing like C macros.
        
         | BatmanAoD wrote:
         | > I'd add a recommendation at the top of this to have a Rust
         | compiler handy.
         | 
         | If you haven't already, check out the Playground:
         | https://play.rust-lang.org/
         | 
         | It's reasonably full-featured for a web IDE (much more so than
         | the Go playground), and it includes many commonly used
         | packages.
         | 
         | > Because on my screen in non-dark mode...
         | 
         | The little sun icon in the lower left corner of the page turns
         | on dark mode! Hopefully that helps.
         | 
         | > I don't understand why b=a; c=a; <-- doesn't work because a
         | is "used up"???
         | 
         | This is something called "linear typing", and it's admittedly
         | pretty unusual in a mainstream language.
         | 
         | The core idea is that the assignment operator _only ever_
         | creates a "shallow" (bitwise) copy of data; it never invokes
         | anything like C++'s copy assignment operator. For types that
         | are "plain old data" (like primitives), the old and the new
         | values are fully independent, so the assignment works the same
         | way it would in most languages, i.e., `a` is not "used up".
         | This is what other commentors mean when they say that
         | primitives "implement `Copy`". But if the old value has
         | pointers or references, then the two values are not
         | independent: after the bitwise copy, they both have pointers to
         | the same data. Since data can only ever be shared explicitly in
         | Rust, and the assignment operator never performs a deep copy,
         | the old value, `a`, is considered invalid and cannot be re-
         | used.
         | 
         | If you're familiar with C++11 or later, one way to think of it
         | is that `=` in Rust always behaves somewhat like `std::move` in
         | C++:
         | 
         | `b = std::move(a);`
         | 
         | The details are substantially different (this will call `a`'s
         | move-assignment operator if one exists, which has no equivalent
         | in Rust, and C++ offers no support for ensuring that `a` is no
         | longer used if its move-assignment operator invalidates it).
         | But the general idea that "move semantics are on by default" is
         | essentially accurate.
        
         | strictfp wrote:
         | Rust is tricky. Took me about a year to grok decently.
         | 
         | Regarding references, the compiler does flow analysis and tries
         | to enforce a sort of static rwlock semantic on variable level.
         | You either have a single mutable reference xor N readable
         | references to the same variable.
         | 
         | If b is a mutable reference to a, c cannot point to a until b
         | reliquishes the "lock", which happens when b goes out of scope.
        
         | coldtea wrote:
         | > _I don 't understand why b=a; c=a; <-- doesn't work because a
         | is "used up"???_
         | 
         | You know how C has a problem with aliases? (multiple variables
         | referencing the same thing)? Which introduce bugs, prevent
         | optimizations, etc?
         | 
         | Well, Rust tries to prevent this, and make more explicit (and
         | known to the compiler) when you do this...
        
           | mikewarot wrote:
           | I've only had a passing acquaintance with C and C++, so I've
           | never used aliases.
           | 
           | I just googled it... why the heck would you copy pointers?
           | That's insane!
           | 
           | In my example, a, b, and c were variables, not pointers.
        
             | coldtea wrote:
             | You keep using this word, variables. I don't think it means
             | what you think it means.
             | 
             | At least in my book pointers are still variables (as in "a
             | pointer variable"), and a variable is any named value,
             | whether it's a scalar or a pointer or a nth-pointer, or
             | what its storage is.
             | 
             | But you mean that in your example there is no way to affect
             | the previous value, right?
             | 
             | > _I just googled it... why the heck would you copy
             | pointers? That 's insane!_
             | 
             | Well, copying values and passing them around would be too
             | costly on memory (for larger structs especially), and would
             | prohibit several techniques.
        
               | mikewarot wrote:
               | Variables can be varied... you can increment, decrement,
               | do whatever you want with them. They keep track of
               | things.
               | 
               | Pointers are used reference things allocated from the
               | heap, and never anything else, unless you're insane.
               | Pointers get directly handled in linked lists, trees,
               | etc.
               | 
               | If at all possible, pointers should be avoided otherwise.
               | 
               | Values passed to a procedure can be done by value (the
               | default in Pascal), or by reference (VAR parameters).
               | 
               | I don't see why anyone wouldn't copy values by default...
               | it is the only sane way to do things.
        
               | twic wrote:
               | > Pointers are used reference things allocated from the
               | heap, and never anything else, unless you're insane.
               | 
               | People routinely use pointers to things on the stack in
               | several languages. Rust even makes it safe to do that,
               | using lifetimes - a pointer to something on the stack
               | can't outlive the stack frame it points into.
               | 
               | > I don't see why anyone wouldn't copy values by
               | default...
               | 
               | Because not everything is safe to copy. In particular,
               | Rust has a few kinds of pointers which come with special
               | rules.
               | 
               | Firstly, it has boxes, which always point to something on
               | the heap, and have a rule that that when the pointer
               | dies, the thing it points to gets freed. If you copied a
               | box, then when one of the copies died, the thing would be
               | freed, and then the other copy would have a pointer to
               | invalid memory, which would be bad.
               | 
               | Secondly, it has mutable references, which come with a
               | guarantee that a mutable reference is the _only_ pointer
               | to a given thing. If you copied a mutable reference, you
               | would break that guarantee.
               | 
               | Thirdly, it has reference-counting pointers (these are in
               | the standard library, not the language). You can make
               | duplicates of those, but they have to increment their
               | reference count when you do so. Copying is always just a
               | bitwise copy, so there is no chance to increment the
               | reference count. Instead, duplication is an explicit
               | operation.
               | 
               | There are a few other things it doesn't make sense to
               | copy. Like, what would it mean to copy a mutex?
               | 
               | So, in Rust, you can't copy by default. However, it is
               | really easy to mark a type as being copyable (the
               | compiler will check that it really is, ie doesn't contain
               | any non-copyable things), and then you can copy it.
        
               | coldtea wrote:
               | > _Variables can be varied... you can increment,
               | decrement, do whatever you want with them. They keep
               | track of things._
               | 
               | You can do the same to a pointer in languages that have
               | them, either directly (e.g. in C) or through some
               | "unsafe" construct (e.g. in Rust, C#, Go).
               | 
               | > _I don 't see why anyone wouldn't copy values by
               | default... it is the only sane way to do things._
               | 
               | When resources are ample, yes. Not the case historically,
               | or in many use cases today.
               | 
               | And not all values make sense to copy.
               | 
               | But also in Rust, we're talking in the context of C
               | performance needs, memory models, and concepts, and Rust
               | expands and makes those safe.
        
               | AsyncAwait wrote:
               | > Variables can be varied... you can increment,
               | decrement, do whatever you want with them.
               | 
               | Variables by themselves are not much. They inherit the
               | properties of the type they are bound to. So what you can
               | do with them can be as restrictive or as permissive as
               | the type allows. That type can be a pointer/reference as
               | well.
        
             | AsyncAwait wrote:
             | > why the heck would you copy pointers?
             | 
             | Pointer aliasing is not always obvious.
        
         | fasterthanlime wrote:
         | It's definitely a lot to take in, you have the right idea --
         | the compiler is here to help, the diagnostics are wonderful and
         | improving every week thanks to the work of Esteban Kuber and
         | others.
         | 
         | Re macros: try to keep an open mind if you can, C macros and
         | Rust macros are completely different. You can get very far
         | without reaching for them, so don't worry too much!
        
         | k__ wrote:
         | _" I don't understand why b=a; c=a; <-- doesn't work because a
         | is "used up"???"_
         | 
         | Had the same issue a few months ago.
         | 
         | The pointer can only be referenced by one variable at a time.
         | 
         | If you "move" the pointer from a to b then a is figuratively
         | "used up" because a is now blocked from doing anything with the
         | pointer anymore.
         | 
         | I guess, for Rust itself the pointer is still referenced by a,
         | Rust just blocks you from using it. But thinking you moved it
         | to another variable helped me a bit.
        
           | mikewarot wrote:
           | if I say
           | 
           | a = 2; b = a; c = a;
           | 
           | There's no pointer in there, just 2.
        
             | rcxdude wrote:
             | That will work fine, because 2 is 'Copy', so it can be
             | copied trivially (as are structs consisting only of Copy
             | members which are marked as Copy). Roughly speaking
             | anything with a pointer in it isn't Copy, though many
             | objects will implement Clone, which basically just means
             | you need to explicitly call .clone() to make a copy instead
             | of it happening implicitly.
        
               | mikewarot wrote:
               | 2 is Copy? It's an integer, could be 2.0 if you wanted to
               | make it a float.
               | 
               | Someone needs to explicitly nail down the mission
               | statement of Rust... because to me it seems to be
               | 
               | "Rust will introduce pointers where they don't need to
               | be, and then try to protect you from the results with
               | obsessive rules"
        
               | AsyncAwait wrote:
               | You need to seriously read more on Rust before making
               | judgments. You're clearly confused.
               | 
               | What '2 is Copy' means precisely that Rust WILL NOT
               | 'introduce pointers where they don't need to be' - 2 is
               | fine to 'alias' because it's a primitive type and so a
               | copy is made when you do that, (i.e. the type implements
               | the 'Copy' trait). However when you do that with complex
               | types that do not implement Copy, you're moving ownership
               | to the new variable so cannot use the old one any more.
        
               | zRedShift wrote:
               | Yes, primitive types all implement Copy.
               | 
               | Maybe playing around with the code would help you better,
               | because that last line doesn't make any sense:
               | https://play.rust-
               | lang.org/?version=stable&mode=debug&editio...
        
               | fasterthanlime wrote:
               | I wrote a piece that tries to explain Rust's memory
               | management strategy, compared to C:
               | https://fasterthanli.me/articles/declarative-memory-
               | manageme...
               | 
               | Hope it helps!
        
       | dperalta wrote:
       | This is exactly what I need it <3
        
       | timhigins wrote:
       | A half-hour to learn Rust Jan 27, 2020 * 51 minute read * rust
       | 
       | maybe the site's reading time estimator is broken? sarcasm
       | intended.
       | 
       | But seriously, it is good to have people writing things like
       | this.
        
         | stonecharioteer wrote:
         | I worked my way through the entire article, typing in each code
         | example. Took me about 3 hours.
        
         | oblio wrote:
         | Firefox' reader mode estimates it at 35-45, if that helps :-)
        
         | AlchemistCamp wrote:
         | > maybe the site's reading time estimator is broken?
         | 
         | All of them are. I first started disliking Medium for just that
         | reason.
        
         | keyle wrote:
         | Programmers don't read, they skim in half the time, then auto-
         | complete in their mind with false assumptions!
        
           | [deleted]
        
           | pjmlp wrote:
           | And then try to write a GUI in Rust.
        
             | artursapek wrote:
             | The state of that art is improving quickly:
             | https://github.com/hecrj/iced
        
               | adwn wrote:
               | Maybe the state of the art for _immediate mode GUIs_ ,
               | but not everyone is hopping onto that bandwagon.
        
               | pjmlp wrote:
               | Doesn't do localization or integration with assistive
               | technologies of the host platform, does it?
        
               | artursapek wrote:
               | No not yet.
        
           | Fannon wrote:
           | Is there a name for this behavior? Sounds like something that
           | is categorized as a cognitive bias?
           | 
           | I'm confident that this does not only apply to programmers :)
        
             | coldtea wrote:
             | It's the cognitive bias cognitive bias (the idea that every
             | random mistaken behavior can be categorized as a congnitive
             | bias).
        
           | mariodiana wrote:
           | Ouch! And just in time for New Year's resolutions. Thanks!
        
           | brabel wrote:
           | That would explain so many of the comments you read on HN and
           | Reddit!
        
         | eeZah7Ux wrote:
         | > maybe the site's reading time estimator is broken? sarcasm
         | intended.
         | 
         | It was not rewritten in rust?
        
         | coldtea wrote:
         | > _maybe the site 's reading time estimator is broken_
         | 
         | No, it's just made for prose, not tutorials.
        
           | fasterthanlime wrote:
           | Yep, code is a lot of "words" which throws off the estimate.
           | I need to address this, but I don't think completely ignoring
           | code blocks is really the solution there.
        
             | kangalioo wrote:
             | Maybe you could estimate the reading time of a code snippet
             | by taking the square root of the number of lines of code? I
             | imagine that the larger the code snippet, the more
             | irrelevant boilerplate it contains, so the square root
             | might be a good way to model this
        
         | internet_user wrote:
         | half-hours is only the compilation time.
        
           | fasterthanlime wrote:
           | Sarcasm aside, the Rust compiler has gotten a lot faster (and
           | parallelizes better) over the last year thanks to Nicolas
           | Nethercote and others.
           | 
           | Another thing few people realize is that the "incremental"
           | compilation mode that's the default for debug builds can also
           | be enabled for release builds!
           | 
           | In CI, something like sccache can help a lot (using the GCS
           | or S3 backend). It makes GitHub Actions' two-core limit
           | almost bearable. Almost.
        
           | pwdisswordfish6 wrote:
           | Per snippet.
        
         | swazzy wrote:
         | I'm guessing the code snippets are skewing the estimate.
        
       | mraza007 wrote:
       | Literally the most easiest way to understand Rust.
       | 
       | Just want to take a moment a appreciate your efforts for writing
       | this amazing article. Honestly it made it so easier to understand
       | Rust especially for a beginner like me
        
       | baby wrote:
       | Usually I would recommend learnXinYminutes.com for that
        
       | archon wrote:
       | Preface: This is an honest question, not an attempt to start a
       | "which language is better" war.
       | 
       | I'm proficient in C#. I haven't yet encountered any problems I
       | can't solve with C# and the .Net open source ecosystem. (Perhaps
       | that says more about the banality of the problems I'm solving
       | than about .Net, but there you are.)
       | 
       | What would Rust give me the tools to do that I can't already
       | accomplish with C# / .Net Core?
        
         | damnyou wrote:
         | Control over 95th+ percentile latency.
        
         | emrah wrote:
         | Rust is a systems (i.e. lower level) language similar to C and
         | C++ that can be compiled to native standalone executables.
         | 
         | If you're primarily doing app dev work, be it desktop or web,
         | you wouldn't really benefit much from it. Although I think Rust
         | code can be compiled to wasm so you could use it as part of
         | webdev work.
         | 
         | You might also find this an interesting read from the same
         | author: https://fasterthanli.me/articles/i-am-a-java-csharp-c-
         | or-cpl...
        
         | oddx wrote:
         | Predictable (low) pauses. Ability to (easily) embed into other
         | language/app as library/plugin.
        
       | Barrin92 wrote:
       | >In this article, instead of focusing on one or two concepts,
       | I'll try to go through as many Rust snippets as I can
       | 
       | I really like this. One of the things I like to do when learning
       | a new language is to go to
       | http://www.rosettacode.org/wiki/Rosetta_Code and just go through
       | snippet examples for certain common tasks.
       | 
       | Just quickly going through examples to me feels much easier than
       | trying to learn from principles.
        
       | skc wrote:
       | This is actually fantastic.
       | 
       | Wish more language tutorials were exactly like this, no fluff.
        
       | Sander3Utile wrote:
       | Here is another similar resource for learning new programming
       | language's on the fly
       | 
       | https://learnxinyminutes.com/
        
       | Animats wrote:
       | That is the best article on Rust I've ever seen. Better than the
       | Rust book. I've been saying that Rust needed a book that wasn't
       | written by the designers of the language, who are too close to
       | it. Now we have one.
        
         | Xunjin wrote:
         | Rust Crash Course by Michael Snoyman is great. You can get a
         | free copy at fpcomplete.
         | 
         | Did a free course in December with him, and I'm still watching
         | the classes because it has so much great info there.
         | 
         | Also I do recommend the Rust Programming, it really teaches you
         | "how/why" use Rust.
         | 
         | To conclude, rust-learning (at GitHub) have great links,
         | amazing articles about parts of the language, there is so much
         | knowledge there, just go collect it :P
        
           | nobleach wrote:
           | Link for those interested:
           | https://www.snoyman.com/blog/2018/10/introducing-rust-
           | crash-...
        
         | nobleach wrote:
         | I'd LOVE it if we could get a Why's Poignant Guide To Rust... I
         | find that kind of weird humor helps my mind remember things.
        
         | christiansakai wrote:
         | This article is very very basic beginner Rust. You'll be
         | disappointed if you expect to encounter Rust in real world like
         | this article.
        
         | [deleted]
        
         | jjice wrote:
         | Out of curiosity, what don't you like about the Rust book? I
         | personally loved it, reading about a year and a half ago. I
         | thought they covered most of what I needed, was well written,
         | and had plenty of good examples.
        
           | steveklabnik wrote:
           | Not all writing clicks with every reader, it is impossible.
           | 
           | He previously said "That's too hard for an introductory book
           | and not detailed enough for a reference manual." It is _very_
           | difficult to get this right, given our goals, and so
           | reasonable people may think we fall short there.
        
         | dbaupp wrote:
         | You may be also interested in the many existing teaching
         | resources published by non-language-designers (whatever that
         | means for a community-driven project like Rust), such as
         | Rustlings and Rust by Example at https://www.rust-
         | lang.org/learn if the book doesn't satisfy whatever criterion
         | you think disqualify it. Some of it is published via the rust-
         | lang.org website, but it was/is maintained by different people
         | who work on the language, compiler, std lib (etc). The project
         | has a large number of people across many teams:
         | https://www.rust-lang.org/governance
        
         | timClicks wrote:
         | There are a few other well regarded resources. _Programming
         | Rust_ from Blandy, Orendorff, and Tindall /O'Reilly is great if
         | you have lots of knowledge in C/C++. _Rust in Action_ from
         | McNamara /Manning is great if you prefer to learn by building
         | projects.
         | 
         | Disclaimer: am the author of Rust in Action
        
         | tgv wrote:
         | But it only covers the very basics. Disclaimer: I've only
         | scrolled through it, but the code snippets are all small. It
         | does show an admirable amount of Rust's syntax, but it's not
         | very discoverable, whereas the book is reasonably well
         | structured (although not for novices, who have forgotten a
         | specific term). The link also doesn't deal with larger
         | programs: there's not an Rc<T> on the page, let alone something
         | like an Arena and unsafe code, and it's really necessary for
         | complex programs.
         | 
         | So, IMO: not better than the Rust book. It gives a first glance
         | of Rust, something to accustom the eyes to a different syntax,
         | but sidesteps the difficult bits, which can make transitioning
         | so frustrating.
        
           | Aeolun wrote:
           | I don't think you should have much unsafe code as a rust
           | beginner.
        
           | trumpeta wrote:
           | There are plenty of cases where you can write a complex
           | program in Rust without ever needing those things.
        
           | lordnacho wrote:
           | I've favourited the article. It's a good complement to the
           | Rust Book, which has more detail. This kind of summary doc is
           | great for discovery, you skim it and you find something that
           | you could have written differently, or you realise there's an
           | idiom you weren't using.
           | 
           | No substiture for the book, though.
        
           | fasterthanlime wrote:
           | I have a _lot_ of Rust articles[1] that go into a lot more
           | depth. They 're mostly adventures though, we learn about
           | ICMP, ELF, file systems etc.
           | 
           | Some love that style (the detours, the stream of
           | consciousness) and some can't stand it. The Rust book is
           | excellent, and a completely different style -- they're
           | complementary!
           | 
           | [1]: https://fasterthanli.me/tags/rust
        
           | EugeneOZ wrote:
           | It's your opinion and I'm not arguing: a lot of people love
           | the Rust book, but some (including me) simply can't read it
           | because of the style of writing and cases when you discover
           | some interesting and deep topic but the author just gives 1
           | example in 5-10 lines of code and that's all. I think that
           | things like Mutexes or Boxes are deep enough to have 30-50
           | pages dedicated to them, and I can say this not only about
           | Mutexes and Boxes. When explaining some powerful things, one
           | need not only explain how they work, but also what kinds of
           | real tasks they can solve - ways of usage are obvious for you
           | when you know it and have experience of usage them, but
           | absolutely opaque and not obvious when you reading about them
           | for the first time.
        
             | ibraheemdev wrote:
             | I highly recommend Jon Gjenset's streams for more advanced
             | Rust concepts like lifetimes or interior mutability. He
             | goes into depth explaining how they work, what kinds of
             | problems they solve, and gives tons of great examples.
        
       | nindalf wrote:
       | > And here's a toilet closure: |_| ()
       | 
       | > Called thusly because |_| () looks like a toilet.
       | 
       | Pure poetry!
       | 
       | Real talk though, this is a great introduction.
        
         | jerrre wrote:
         | I've been staring at this for a minute, but please help me
         | seeing a toilet in this? Is it a top down view perhaps?
        
           | kyrrewk wrote:
           | toilet seat up
        
             | jackric wrote:
             | which bit is the toilet seat?
        
               | AlexSW wrote:
               | The seat is to the right (the ( )) and the water tank (?)
               | is on the left.
        
               | matt_kantor wrote:
               | I made a visual: https://i.imgur.com/VgsDidE.jpg
        
         | CJefferson wrote:
         | I often use the "owl" <(),()>, usually in Result<(),()>.
        
           | brabel wrote:
           | Why use a Result whose error type is empty?
        
             | CJefferson wrote:
             | I should have said :) I am writing backtracking algorithms
             | (think something like a Sudoku solver where we fill in
             | values by guessing), and an 'Error' is when we can deduce
             | the Sudoku cannot be filled in, so we have to backtrack.
             | 
             | I find Rust's ? notation gives a very natural way of
             | writing such algorithms. I don't care "why" filling in the
             | Sudoku failed, particularly because the solver will
             | typically fail millions of times a second, so I definately
             | don't want constructing the error to be expensive in any
             | way.
        
               | jackric wrote:
               | I would suggest Option is the more semantic type to use
               | for your situation - None indicating no valid solution on
               | this path
        
               | CJefferson wrote:
               | Oh, today I learned the ? operator works with Option as
               | well as Result! I might try that out, thanks.
        
               | cesarb wrote:
               | IIRC, it didn't work with Option in the past, so you
               | might have been correct when your code was written. The ?
               | operator came originally from the try!() macro, which was
               | specific to Result; unlike the macro, it was designed to
               | be extensible through the still-unstable std::ops::Try
               | trait, but IIRC that trait was initially implemented only
               | for Result, and only later was extended to Option and a
               | couple of others.
        
       | l00sed wrote:
       | I've mostly used web-specialized programming languages like
       | JavaScript and PHP, and some Python. Some of the unique
       | characteristics of Rust have been trickier for me to pick up.
       | 
       | This looks like a fun and useful article, but I'd also recommend
       | Rustlings to anyone interested in learning Rust.
       | 
       | https://github.com/rust-lang/rustlings
        
       | IshKebab wrote:
       | This is very good although the title definitely promises too
       | much!
        
       | redisman wrote:
       | There wasn't anything on concurrency or asynchronous programming
       | (like a http client). Is there a good resource for those parts of
       | the language?
        
         | fasterthanlime wrote:
         | The closest I've written is this:
         | https://fasterthanli.me/articles/getting-in-and-out-of-troub...
         | but it explicitly seeks the complicated bits because
         | elucidating those is the whole point of the article.
         | 
         | I might write another one that focuses on the happy path.
        
       | akavel wrote:
       | Newbie question: in the last example:                 fn
       | make_tester(answer: &str) -> impl Fn(&str) -> bool + '_ {
       | move |challenge| {               challenge == answer           }
       | }
       | 
       | why is there `move` needed, if both `answer`, and the arg of
       | `Fn`, seem to be references (`&str`)? To a layman, this sounds
       | like as if both "challenge" and "answer" should be borrowed - so
       | why "move"? what's even to move here?
        
         | steveklabnik wrote:
         | I _believe_ what happens here is that the closure tries to
         | capture it as a  &&str. This is because it defaults to trying
         | to take the environment by reference. The "move" in this case
         | means that it will try to take it by value instead. This feels
         | tricky semantically because references are types too, so
         | "taking it by value" means taking a &T rather than a &&T, just
         | like you may think about how taking a T is by value as opposed
         | to &T.
        
         | ridiculous_fish wrote:
         | This is confusing, and Rust's error messages make it much
         | worse. If you try to remove the `move`, you get an error:
         | 
         | > closure may outlive the current function, but it borrows
         | `answer`, which is owned by the current function. To force the
         | closure to take ownership of `answer` use the `move` keyword.
         | 
         | But 'answer' is of course not owned by the current function,
         | and how can you take ownership through a shared reference?
         | 
         | The explanation is double indirection. By default, the closure
         | captures a pointer to answer, which is itself a pointer on the
         | stack. Without the 'move', inside the closure `answer` has type
         | &&str and points into make_tester's stack frame. With the
         | 'move', it copies the passed-in pointer. The error message is
         | referring to the pointer itself, and this is not obvious.
         | 
         | Incidentally I have never found docs for the '+' syntax there,
         | would appreciate a pointer to any.
        
           | steveklabnik wrote:
           | The + syntax is https://doc.rust-
           | lang.org/reference/types/trait-object.html#...
           | 
           | This applies to impl Trait as well. It should probably be
           | there too...
        
             | ridiculous_fish wrote:
             | Thanks!
        
         | Rotten194 wrote:
         | Iirc it's moving the reference to answer, not the value.
        
         | momothereal wrote:
         | In this closure you are moving `answer`, that is, you are
         | moving the reference itself into scope. The `challenge`
         | reference is already owned by the closure since it's a
         | parameter. The move doesn't mean the closure owns the
         | underlying strings, but the references themselves.
        
       | mkl95 wrote:
       | I like Derek Banas' approach. He makes introductory videos for
       | several languages.
       | 
       | They are suited for developers who already have some experience
       | in another language, and they last from 45 minutes to 2 1/2
       | hours.
       | 
       | https://www.youtube.com/watch?v=U1EFgCNLDB8
        
       | Tade0 wrote:
       | There's a lot of valuable, condensed knowledge here, but for
       | those who wish to learn the language in a more interactive way I
       | recommend Rustlings:
       | 
       | https://github.com/rust-lang/rustlings
       | 
       | I spent the last two weeks going through it and so far the
       | experience has been great. There's a quiz at the end of most
       | chapters.
        
         | miccah wrote:
         | I have been learning rust interactively with Exercism, which
         | uses a mentor system to provide feedback and suggestions.
         | 
         | https://exercism.io/tracks/rust
         | 
         | It's also great to view other learner's solutions once you
         | complete the exercise.
        
         | noisy_boy wrote:
         | I have been doing the rustlings exercises (which are basically
         | exercises to fix errors on various topics) - they are just the
         | right size to keep you engaged and continuing because they
         | reward you with success. Also its very easy to leave it
         | anywhere and resume exactly the same point or go back to an old
         | exercise and retry it. Plus because its just code organized in
         | a directory, you can leverage all the feature of your favorite
         | IDE. Highly recommended.
        
       | bbx wrote:
       | In similar fashion you can learn "Web Design in 4 minutes" [1]
       | and "JavaScript in 14 minutes" [2]
       | 
       | [1] https://jgthms.com/web-design-in-4-minutes/
       | 
       | [2] https://jgthms.com/javascript-in-14-minutes/
        
       | dnautics wrote:
       | I spun up a roughly equivalent version of this for Zig, I would
       | say this is about 70% of the language:
       | 
       | https://gist.github.com/ityonemo/769532c2017ed9143f3571e5ac1...
        
       | techolic wrote:
       | let x;       foobar(x); // error: borrow of possibly-
       | uninitialized variable: `x`       x = 42;
       | 
       | possibly-uninitialized - Why does the compiler sound uncertain
       | while emitting an error?
        
         | steveklabnik wrote:
         | The analysis is not perfect. It's worded that way to
         | acknowledge this fact.
         | 
         | It also is language that works well when something may be
         | initialized in some control flow paths but not all.
        
       | ibraheemdev wrote:
       | I was inspired by this article and wrote "Twenty minutes to learn
       | Go" [0]. Go being a much simpler language than Rust, I feel that
       | anyone who knows a programming language can become productive in
       | Go in less than an hour. Of course this simplicity comes at the
       | cost of increased boilerplate, less expressiveness...
       | 
       | 0: https://ibraheem.ca/posts/go-in-twenty
        
       | inancgumus wrote:
       | [dup] duplicate https://news.ycombinator.com/item?id=22448933
        
       | dmitshur wrote:
       | For anyone curious what a Go version of the same article would
       | look like (as I was), I tried to answer that question by writing
       | https://dmitri.shuralyov.com/blog/27.
        
         | dnautics wrote:
         | thanks for inspiring me, I did one for zig as well:
         | 
         | https://gist.github.com/ityonemo/769532c2017ed9143f3571e5ac1...
        
         | faitswulff wrote:
         | I enjoyed this, thank you!
        
           | walkingolof wrote:
           | Comments like this are to far in-between on the internet,
           | kudos!
        
       | mojuba wrote:
       | (Side note: dear Apple, please add syntax coloring and code
       | formatting for Rust to Xcode. You have Fortran and C Shell in the
       | list, but not Rust or Go, which are much more popular!)
        
         | speedgoose wrote:
         | Is there any reason to use Xcode for Rust development?
        
           | mojuba wrote:
           | It's a habit. Keyboard shortcuts, familiar bugs and glitches,
           | etc are not easy to change.
        
       | [deleted]
        
       | elvongray wrote:
       | Reminds me of this also: https://cheats.rs/
        
       | dmurray wrote:
       | Great article.
       | 
       | I've never used Rust before so I'm exactly the target audience. I
       | first got tripped up around
       | 
       | > Trait methods can also take self by reference or mutable
       | reference:                 impl std::clone::Clone for Number {
       | fn clone(&self) -> Self {             Self { ..*self }         }
       | }
       | 
       | What's the asterisk doing in this code? I guess it's
       | destructuring the struct somehow, but I don't see that syntax
       | elsewhere: destructuring was introduced but looked like it worked
       | without the star. Alternatively, it's dereferencing the
       | reference, but that seems less likely.
        
         | pornel wrote:
         | It is dereferencing. It changes `&self` to `self`. The `..`
         | operator wants a value, not a reference.
        
           | Aeolun wrote:
           | So the & and * can basically be left out to make 'self' a
           | value from the start?
        
             | rcxdude wrote:
             | technically yes, but it'll change the semantics in a not
             | useful way. Because if you leave off the & on self then the
             | method won't borrow self (take it by reference) but consume
             | it (take it by value by 'moving' it), so you can't use it
             | any more after calling clone(), which basically makes the
             | method a no-op instead of copying the struct.
        
               | dmurray wrote:
               | Thanks pornel and rcxdude, this makes sense to me now. I
               | was thinking it shouldn't be dereferencing because when
               | references were previously introduced (the print_number
               | example), we could call methods on the reference without
               | any special syntax. But I guess it makes sense that
               | instance methods work that way, while other functions
               | need to know if we have a reference or the real object,
               | and in this regard it works more or less like C++.
        
         | st1x7 wrote:
         | I also find some of the syntax peciliarities and their
         | combinations difficult to look up. In addition to & and *,
         | there's question marks, dots, double dots,
         | square/round/triangle brackets, empty parentheses and
         | apostrophes all over the place and it makes it really difficult
         | to deconstruct what's happening in a block of code.
        
       | runjake wrote:
       | I like to use LearnXInYMinutes as my first stop for learning a
       | new language.
       | 
       | Often, I end up being able to get started right away, but at
       | worst, it gives me an accelerated start into tougher cookies like
       | Rust.
       | 
       | https://learnxinyminutes.com/
        
       ___________________________________________________________________
       (page generated 2021-01-02 23:01 UTC)