While I am only a Rust novice it seems to me like the "2.2 Item 11: Implement the Drop trait for RAII patterns" could use some kind of mention of Drop-leaks. I learned about it at https://doc.rust-lang.org/nightly/nomicon/leaking.html
- You can't export a reference to the thing you are dropping. You can do that in C++. This prevents "re-animation", where something destroyed comes back to life or is accessed beyond death. Microsoft Managed C++ (early 2000s), supported re-animation and gave it workable semantics. Bad idea, now dead.
- This is part of why Rust destructors cannot run more than once. Less than once is possible, as mentioned above.
- There's an obscure situation with Arc and destructors. When an Arc counts down to 0, the destructor is run. Exactly once. However, Arc countdown and destructor running are not an atomic operation. It is possible for two threads to see an Arc in a strong_count == 1 state just before the Arc counts down. Never check strong_count to see if you are "the last owner". That creates a race condition.[1] I've seen that twice now. I found race conditions that took a day of running to hit. Use strong_count only for debug print.
- A pattern that comes up in GUI libraries and game programming involves objects that are both in some kind of index and owned by Arcs. On drop, the object should be removed from the index. This is a touchy operation. The index should use weak refs, and you have to be prepared to get an un-upgradable Weak from the index.
- Even worse is the case where dropping an object starts a deletion of something else.
If the second deletion can't be completed from within the destructor, perhaps because it requires a network transaction, it's very easy to introduce race conditions.
Managed C++ is pretty much around, kind of, as it got replaced by C++/CLI in .NET 2.0, is still used by many of us instead of dealing with P/Invoke annotations, is required by WPF infrastructure, and currently is on C++20 support level.
> - You can't export a reference to the thing you are dropping. You can do that in C++. This prevents "re-animation", where something destroyed comes back to life or is accessed beyond death. Microsoft Managed C++ (early 2000s), supported re-animation and gave it workable semantics. Bad idea, now dead.
>
> - This is part of why Rust destructors cannot run more than once. ...
This is a very backwards way to describe this, I think. Managed C++ only supported re-animation for garbage collected objects, where it is still today a fairly normal thing for a language to support. This is why these "destructors" typically go by a different name, "finalizers." Some languages allow finalizers to run more than once, even concurrently, but this is again due to their GC design and not a natural thing to expect of a "destructor."
The design of Drop and unmanaged C++ destructors is that they are (by default) deterministically executed before the object is deallocated. Often this deallocation is not by `delete` or `free`, which could perhaps in principle be cancelled, but by a function return popping a stack frame, or some larger object being freed, which it simply does not make sense to cancel.
> Never check strong_count to see if you are "the last owner".
This made me think of the `im` library[0] which provides some immutable/copy on write collections. The docs make it seem like they do some optimizations when they determine there is only one owner:
> Most crucially, if you never clone the data structure, the data inside it is also never cloned, and in this case it acts just like a mutable data structure, with minimal performance differences (but still non-zero, as we still have to check for shared nodes).
I hope this isn't prone to a similar race condition!
The way to do this while avoiding race conditions seems to be `Arc::into_inner` or `Arc::get_mut`; for instance, the docs for `Arc::try_unwrap` mention a possible race condition, and recommend using `Arc::into_inner` to avoid it: https://doc.rust-lang.org/std/sync/struct.Arc.html#method.tr...
The important note here is that you can't rely on Drop running in order to satisfy the SAFETY comment of an unsafe block. In practice, in safe Rust, this knowledge shouldn't really change how you write your code.
It’s not that surprising when you consider that “unsafe” only concerns itself with memory safety. mem::forget is not unsafe from that perspective.
> In the past mem::forget was marked as unsafe as a sort of lint against using it, since failing to call a destructor is generally not a well-behaved thing to do (though useful for some special unsafe code). However this was generally determined to be an untenable stance to take: there are many ways to fail to call a destructor in safe code. The most famous example is creating a cycle of reference-counted pointers using interior mutability.
I agree that Rust can look pretty weird to an untrained developer when lifetimes get involved. But, in Rust's defence, I haven't seen any other language write down lifetimes more concisely.
The underscore could've been a name if the name mattered, which would be required in many languages. Rewriting it to <'something>) may help readability (but risks introducing bugs later by reusing `something`).
Many C-derived languages are full of symbol soup. A group like <?,?>[]) can happen all over Java, for instance. Many of these languages have mixes of * and & all over the place, C++ has . and -> for some reason, making for some pretty unreadable soup. The biggest additions I think Rust added to the mix was ' for lifetimes (a concept missing from most languages, unfortunately), ! for a macro call (macro invocations in many other languages aren't marked at all, leaving the dev to figure out if println is a method or a macro), and ? to bubble up errors. The last one could've been a keyword (like try in Zig) but I'm not sure if it makes the code much more readable that way.
If you know other programming languages, the symbols themselves fall into place quite quickly. I know what <'_> does in Rust for the same reason I know what <T, R> T does in Java, while a beginner or someone who hasn't learned past Java 6 may struggle to read the code. Out of all the hurdles a beginning Rust programmer will face, the symbols are probably your least concern.
As for books, the Rust book on the Rust website is kept up to date pretty well. There are books for programmers coming from various other languages as well.
The language itself hasn't changed much these past few years. The standard library gets extended with new features, but a book a few years old will teach you Rust just fine.
In many cases, changes to the language have been things like "the compiler no longer treats this as broken (because it isn't)" and "the compiler no longer requires you to write out this long definition because it can figure that stuff out itself". I'd recommend running a tool called "clippy" in your IDE or on the command line, if you can leverage a modern language feature for better legibility, clippy will usually suggest it.
> I agree that Rust can look pretty weird to an untrained developer when lifetimes get involved. But, in Rust's defence, I haven't seen any other language write down lifetimes more concisely.
Can you do a lot better? I don't think so and it wouldn't help that much.
The truth is that most of the time we want to rely on some inferred lifetime annotations, but will obviously need an escape hatch from time to time.
Rust doesn't waste a lot of typing around the annotations, but if you were to improve Rust, you'd improve the implicit inference, not the syntax for being explicit.
(not OP)
I love rust, bu I just think that using ' for lifetime was a huge mistake, and using <> for templates (rather than something like []) was a medium mistake.
There is something about how the brain is wired, that using ' for lifetime, just triggers the wrong immediate response to it.
Something like this would look so much nicer IMHO [$_], compared to this <'_>.
Symbols are just other letters in the alphabet. Something like <‘_> is as natural for me to read at this point as any of the other words in this sentence.
Math is also symbol soup. But those symbols mean things and they’ve usually been designed to compose nicely. Mathematicians using symbols—just like writers using alphabets—are able to use those symbols to concisely and precisely convey complicated concepts to one another.
I guess my point is that symbols shouldn’t be looked at as inherently a positive or negative thing. Are they clear and unambiguous in their use? Do they map clearly onto coherent concepts? When you need to compose them, is it straightforward and obvious to do so?
I think many programming languages could benefit if we had an easy way to have both custom symbols and a convenient way to input them without extra friction. Take APL for example, once you know the language it's incredibly expressive, but the overhead to typing it is so strong that many use custom keyboards/caps.
Uiua (https://www.uiua.org/), broadly in the APL lineage, solves this problem nicely.
Like APL, it has a set of well-chosen symbols, but each symbol has an english name you can type just as you would a function name in another language, and it's automatically converted to the symbol when you run it.
To be fair the basic ASCII keyboard is also default in US/Britain. And most people assume that's all they get.
I have always used the "international" version of the US English keyboard on Linux.
And I can enter all common symbols pressing altgr or altgr-shift. I also use right Ctrl as a compose key fore more. I would be hard pressed remembering what combo to press, after years it's just muscle memory.
But how do you find out what layout and what compose key does what? Good luck. It's as documented as gesture and hidden menus on iOS and MacOS. sigh.
> Math is also symbol soup. But those symbols mean things and they’ve usually been designed to compose nicely. Mathematicians using symbols—just like writers using alphabets—are able to use those symbols to concisely and precisely convey complicated concepts to one another.
I just don't understand why one may take maths of all things as a positive example of something readable, when it's widely known to be utterly inscrutable to most humans on earth and even so many papers have differing conventions, using the same symbol for sometimes widely different or sometimes barely different things
Even something like foo::<‘_, [T]>() is just not that hard to follow. Again, the symbols involved all compose nicely and are unambiguous. And frankly, you just don’t need something like that all that often (and when you do, there are usually other alternatives if you’re really put off by the symbols.
I prefer ("if a, err := bar() {"), the same things you said applies here, too. I write a lot of Go and I can glance through it quickly, there is no cognitive overhead for me.
Edit: actually, it was someone else who said this: "Human brain has a funny way of learning how to turn off the noise and focus on what really matters.".
The difference is, there is no room for bugs with ?. Zero. None.
I have fixed (and frankly, caused) many bugs in golang code where people’s brains “turned off the noise” and filtered out the copypasta’d error handling, which overwrote the wrong variable name or didn’t actually bubble up the error or actually had subtly wrong logic in the conditional part which was obscured by the noise.
Frankly, learning to ignore that 80% of your code is redundant noise feels to me like a symptom of Stockholm syndrome more than anything else.
One symbol to replace three lines of identical boilerplate is no less explicit and dramatically clearer.
It's a curly-brace language with some solid decisions (e.g. default immutability) that produces static binaries and without a need for a virtual machine, while making some guarantees that eliminate a swathe of possible bug types at compile time.
As others note, the symbol soup is something you learn to read fluently and isn't worth getting hung up on.
Basically it occupies something of a sweet spot in the power/useability/safety space and got a decent PR shove by coming out of Mozilla back when they were the cool kids. I like it a lot. YMMV.
<'_> is one of the most basic symbols in Rust. Reading that is almost like reading the letter 'a after just some very modest amount of time with the language.
> How come is it in demand?
Because there's a lot more to the language than just those not-really-unfamiliar symbols
Rust's design is designed to be more in the mentality of if it compiles that it is good enough, leaving less for runtime issues to occur unexpected, dictated by type and memory safety. So, it requires more type info (unless you use unidiomatic unsafe code) and talking with borrow checker. But, once you internalize its type system and borrow checker, it pays off if you care about compiler driven development (instead of dealing with errors in runtime).
Because it's a complicated language for building extremely low level things, when you have no other choice. IMO it's not the right tool for high level stuff (even though it does have some stuff which higher level languages should probably borrow).
The only other language that directly competes with Rust IMO is C++, which is equally full of symbol soup.
> IMO it's not the right tool for high level stuff
I thought that for a long time. But as time passes and I spend more time in languages like Typescript (Semi-Type Script more accurately) and Swift the more I yearn for Rust.
Yeah I feel that, not the entire language but, many of its choices, like error handling, sum types (with exhaustive enum matching) especially when writing in python.
What do you think about Rust for Rustaceans? I read it and there are very niche and useful information there about Rust that I didn't see anywhere. It's a solid book but for a book about programming there are so few real code examples that it can come off dry. I just bought Rust atomic and locks and it seems exercise based, so I'm excited to finish it. The first chapter seems promising
You are right about it not being a beginner friendly book. Hence why I placed it lower in the order of books to study.
Yeah Rust atomics and locks is essential if you truly want to understand low-level concurrency. But you might have to also refer to the C++ std::atomics reference [1] to get a complete idea. It took me a while to grasp those concepts.
"Programming Rust" by Jim Blandy et al was the book that really helped me to understand why many of the design decisions behind the implementation of Rust were made.
I found it more approachable than some of the other Rust books and highly recommend it as a first Rust book.
Unfortunately, I haven't read Programming Rust. The list includes just the books I used to learn Rust. But will definitely give Blandy's book a read. Thanks for the recommendation!
The Rust Programming Language does a great job imho. It got me up to speed by reading it before bed for a month. I’d never written C/C++ before, just a lot of Python. It starts out really simply by explaining the type system and the borrow checker. Take it from there and do a couple of side projects, I’d say.
Why do people say Rust follows the tradition of C++? Rust follows very different design decisions than C++ like a different approach to backwards compatibility, it does not tack on one feature on top of another, it is memory safe etc that are very different from C++. If you are just comparing the size of language, there are other complex languages out there like D, Ada etc
> Why do people say Rust follows the tradition of C++?
They mean the domain that Rust is in.
Before Rust there was only C or C++ for real time programming. C++ was an experiment (wildly successful IMO when I left it in 2001) trying to address the shortcomings of C. It turned out that too much of everything was in C++, long compile times, a manual several inches thick, huge executables. Some experiments turned out not to be a good idea (exceptions, multiple inheritance, inheritance from concrete classes....)
Rust is a successor in that sense. It draws on the lessons of C++ and functional programming.
I hope I live long enough to see the next language in this sequence that learns form the mistakes of Rust (there are a few, and it will take some more years to find them all)
Split ←((⊢-˜+`׬)∘=⊔⊢)
input2←' 'Split¨•file.Lines "../2020/2.txt" # change string to your file location
Day2←{
f←⊑{(⊑)+↕1+|-´}‿{-1} # Select the [I]ndex generator [F]unction
I←{F •BQN¨ '-' Split ⊑} # [I]ndices used to determine if the
C←{⊑1⊑} # [C]haracter appears in the
P←{⊑⌽} # [P]assword either
Part1←(I∊˜·+´C= P)¨ # a given number of times
Part2←(1= ·+´C=I⊏P)¨ # or at one of a pair of indices
⊑+´◶Part1‿Part2
}
•Show { Day2 input2}¨↕2
Lifetimes and annotations only look like symbol soup initially (when you have little to no experience in Rust). The more proficient you become in Rust more you end up ignoring it completely. Sort of like ads you see (or don't) in Search. Human brain has a funny way of learning how to turn off the noise and focus on what really matters.
It was designed to be used with syntax highlighting and LSPs. The highlighting makes it pretty easy to read for me. Although there are some arcane generics with lifetimes that can be indecipherable in some libraries.
Off the bat: I like Rust. I'm still very much a novice with it, but I enjoy it.
But almost the entirety of Computer Science is based on abstractions because they're helpful to "dumb down" some details that aren't super-important for our day-to-day work. E.g., writing TCP protocols directly is Assembly would be too fine-grained detail for most people's usual work, and using some existing abstraction is "good enough" virtually all of the time (even though we might be able to optimize things for our use-cases if we did drop down to that level)
There exists programming work where fiddling with lifetimes is just too fiddly to be worthwhile (e.g., web development, probably is more than fine using a good ol' garbage collected language). This isn't about "dumbing down" anything, it's about refocusing on what's important for the job you're doing.
The last 2 books I’ve bought (ostep and nand2tetris) are available online. Hard copies are nice and personally seeing it on my desk gives more more motivation to finish them.
Because we all know what happens if we're not the customer.
I have this; I bought it because I want to reward the author for producing a quality work, and because I want to encourage the publishers to produce other works that would appeal to me.
I also happen to like physical texts so I bought the paperback but I have this and the digital edition. The latter is convenient for when I am travelling and appropriately formatted for an eReader (not just the raw html from these pages).
> Plus I have money. This book costs about as much as a good bottle of wine or a bad bottle of whiskey.
Exactly.
A few years ago I did a really aggressive weeding out of my bookshelves as things were getting far too cluttered. In the process I threw out what must have been - at cover price - several thousand pounds worth of IT related books.
On the resale market they were all too stale to have any value (though I did manage to give a handful away to friends). In one way it was a bit painful, but those few thousand pounds worth of books has given me a huge (financial) return on that investment!
Cheap at the cost of a good bottle of wine ... for the foundations of a career!
The book isn’t free, its contents are published online by the author. Yes, nitpicking. But (1) I like a well formatted epub and (2) the author/publisher still hold copyright.
Related. Others?
Effective Rust - https://news.ycombinator.com/item?id=38241974 - Nov 2023 (10 comments)
Effective Rust (2021) - https://news.ycombinator.com/item?id=36338529 - June 2023 (204 comments)
Edit: I've put 2024 in the title above because that's what the page currently says. But what's the most accurate year for this material?
Under Preface -> Rust Version, it says "The text is written for the 2018 edition of Rust", but it does seem released in 2024. Interesting.
While I am only a Rust novice it seems to me like the "2.2 Item 11: Implement the Drop trait for RAII patterns" could use some kind of mention of Drop-leaks. I learned about it at https://doc.rust-lang.org/nightly/nomicon/leaking.html
Rust destructors are interesting.
- You can't export a reference to the thing you are dropping. You can do that in C++. This prevents "re-animation", where something destroyed comes back to life or is accessed beyond death. Microsoft Managed C++ (early 2000s), supported re-animation and gave it workable semantics. Bad idea, now dead.
- This is part of why Rust destructors cannot run more than once. Less than once is possible, as mentioned above.
- There's an obscure situation with Arc and destructors. When an Arc counts down to 0, the destructor is run. Exactly once. However, Arc countdown and destructor running are not an atomic operation. It is possible for two threads to see an Arc in a strong_count == 1 state just before the Arc counts down. Never check strong_count to see if you are "the last owner". That creates a race condition.[1] I've seen that twice now. I found race conditions that took a day of running to hit. Use strong_count only for debug print.
- A pattern that comes up in GUI libraries and game programming involves objects that are both in some kind of index and owned by Arcs. On drop, the object should be removed from the index. This is a touchy operation. The index should use weak refs, and you have to be prepared to get an un-upgradable Weak from the index.
- Even worse is the case where dropping an object starts a deletion of something else. If the second deletion can't be completed from within the destructor, perhaps because it requires a network transaction, it's very easy to introduce race conditions.
[1] https://github.com/rust-lang/rust/issues/117485
Managed C++ is pretty much around, kind of, as it got replaced by C++/CLI in .NET 2.0, is still used by many of us instead of dealing with P/Invoke annotations, is required by WPF infrastructure, and currently is on C++20 support level.
> - You can't export a reference to the thing you are dropping. You can do that in C++. This prevents "re-animation", where something destroyed comes back to life or is accessed beyond death. Microsoft Managed C++ (early 2000s), supported re-animation and gave it workable semantics. Bad idea, now dead.
>
> - This is part of why Rust destructors cannot run more than once. ...
This is a very backwards way to describe this, I think. Managed C++ only supported re-animation for garbage collected objects, where it is still today a fairly normal thing for a language to support. This is why these "destructors" typically go by a different name, "finalizers." Some languages allow finalizers to run more than once, even concurrently, but this is again due to their GC design and not a natural thing to expect of a "destructor."
The design of Drop and unmanaged C++ destructors is that they are (by default) deterministically executed before the object is deallocated. Often this deallocation is not by `delete` or `free`, which could perhaps in principle be cancelled, but by a function return popping a stack frame, or some larger object being freed, which it simply does not make sense to cancel.
> Never check strong_count to see if you are "the last owner".
This made me think of the `im` library[0] which provides some immutable/copy on write collections. The docs make it seem like they do some optimizations when they determine there is only one owner:
> Most crucially, if you never clone the data structure, the data inside it is also never cloned, and in this case it acts just like a mutable data structure, with minimal performance differences (but still non-zero, as we still have to check for shared nodes).
I hope this isn't prone to a similar race condition!
[0] https://docs.rs/im/15.1.0/im/index.html
The way to do this while avoiding race conditions seems to be `Arc::into_inner` or `Arc::get_mut`; for instance, the docs for `Arc::try_unwrap` mention a possible race condition, and recommend using `Arc::into_inner` to avoid it: https://doc.rust-lang.org/std/sync/struct.Arc.html#method.tr...
The important note here is that you can't rely on Drop running in order to satisfy the SAFETY comment of an unsafe block. In practice, in safe Rust, this knowledge shouldn't really change how you write your code.
The big foot-gun here is mem::forget rather than Drop itself. Although yeah it is pretty surprising that is considered safe.
It’s not that surprising when you consider that “unsafe” only concerns itself with memory safety. mem::forget is not unsafe from that perspective.
> In the past mem::forget was marked as unsafe as a sort of lint against using it, since failing to call a destructor is generally not a well-behaved thing to do (though useful for some special unsafe code). However this was generally determined to be an untenable stance to take: there are many ways to fail to call a destructor in safe code. The most famous example is creating a cycle of reference-counted pointers using interior mutability.
Yes, thanks, I read the article. Nevertheless, it's still a surprising footgun.
What's unsafe about implicitly "leaking" memory?
Destructors do more than just free memory.
Running out of memory and killing the OS I would guess unless the OS kills misbehaving process first.
Rust is so full of symbol soup.
is a very simple one, but there are ones with ~7 consecutive symbols, and there are a lot of symbols all over Rust code.How come it is in demand?
Cool book though.
I agree that Rust can look pretty weird to an untrained developer when lifetimes get involved. But, in Rust's defence, I haven't seen any other language write down lifetimes more concisely.
The underscore could've been a name if the name mattered, which would be required in many languages. Rewriting it to <'something>) may help readability (but risks introducing bugs later by reusing `something`).
Many C-derived languages are full of symbol soup. A group like <?,?>[]) can happen all over Java, for instance. Many of these languages have mixes of * and & all over the place, C++ has . and -> for some reason, making for some pretty unreadable soup. The biggest additions I think Rust added to the mix was ' for lifetimes (a concept missing from most languages, unfortunately), ! for a macro call (macro invocations in many other languages aren't marked at all, leaving the dev to figure out if println is a method or a macro), and ? to bubble up errors. The last one could've been a keyword (like try in Zig) but I'm not sure if it makes the code much more readable that way.
If you know other programming languages, the symbols themselves fall into place quite quickly. I know what <'_> does in Rust for the same reason I know what <T, R> T does in Java, while a beginner or someone who hasn't learned past Java 6 may struggle to read the code. Out of all the hurdles a beginning Rust programmer will face, the symbols are probably your least concern.
As for books, the Rust book on the Rust website is kept up to date pretty well. There are books for programmers coming from various other languages as well.
The language itself hasn't changed much these past few years. The standard library gets extended with new features, but a book a few years old will teach you Rust just fine.
In many cases, changes to the language have been things like "the compiler no longer treats this as broken (because it isn't)" and "the compiler no longer requires you to write out this long definition because it can figure that stuff out itself". I'd recommend running a tool called "clippy" in your IDE or on the command line, if you can leverage a modern language feature for better legibility, clippy will usually suggest it.
> I agree that Rust can look pretty weird to an untrained developer when lifetimes get involved. But, in Rust's defence, I haven't seen any other language write down lifetimes more concisely.
Can you do a lot better? I don't think so and it wouldn't help that much.
The truth is that most of the time we want to rely on some inferred lifetime annotations, but will obviously need an escape hatch from time to time.
Rust doesn't waste a lot of typing around the annotations, but if you were to improve Rust, you'd improve the implicit inference, not the syntax for being explicit.
(not OP) I love rust, bu I just think that using ' for lifetime was a huge mistake, and using <> for templates (rather than something like []) was a medium mistake.
There is something about how the brain is wired, that using ' for lifetime, just triggers the wrong immediate response to it.
Something like this would look so much nicer IMHO [$_], compared to this <'_>.
I cannot imagine using syntax that’s largely reserved across languages for array indexing for such a completely unrelated topic.
This comes from ML (as in SML or OCaml), where 'a reads "alpha" and is a type parameter.
I completely disagree that [$_] looks nicer than <'_>.
Symbols are just other letters in the alphabet. Something like <‘_> is as natural for me to read at this point as any of the other words in this sentence.
Math is also symbol soup. But those symbols mean things and they’ve usually been designed to compose nicely. Mathematicians using symbols—just like writers using alphabets—are able to use those symbols to concisely and precisely convey complicated concepts to one another.
I guess my point is that symbols shouldn’t be looked at as inherently a positive or negative thing. Are they clear and unambiguous in their use? Do they map clearly onto coherent concepts? When you need to compose them, is it straightforward and obvious to do so?
I think many programming languages could benefit if we had an easy way to have both custom symbols and a convenient way to input them without extra friction. Take APL for example, once you know the language it's incredibly expressive, but the overhead to typing it is so strong that many use custom keyboards/caps.
I wish compose keys were more prevalent. There's something nice about typing -> and getting →
Uiua (https://www.uiua.org/), broadly in the APL lineage, solves this problem nicely.
Like APL, it has a set of well-chosen symbols, but each symbol has an english name you can type just as you would a function name in another language, and it's automatically converted to the symbol when you run it.
To be fair the basic ASCII keyboard is also default in US/Britain. And most people assume that's all they get.
I have always used the "international" version of the US English keyboard on Linux.
And I can enter all common symbols pressing altgr or altgr-shift. I also use right Ctrl as a compose key fore more. I would be hard pressed remembering what combo to press, after years it's just muscle memory.
But how do you find out what layout and what compose key does what? Good luck. It's as documented as gesture and hidden menus on iOS and MacOS. sigh.
> Math is also symbol soup. But those symbols mean things and they’ve usually been designed to compose nicely. Mathematicians using symbols—just like writers using alphabets—are able to use those symbols to concisely and precisely convey complicated concepts to one another.
I just don't understand why one may take maths of all things as a positive example of something readable, when it's widely known to be utterly inscrutable to most humans on earth and even so many papers have differing conventions, using the same symbol for sometimes widely different or sometimes barely different things
Literally every language is inscrutable to most humans on Earth. But they all work fairly well for those in the club that know them!
Well, I wish I could find the ones I have seen in the wild.
Perhaps HRTBs and Fn traits, or double turbofish generics. I really cannot remember sadly.
Even something like foo::<‘_, [T]>() is just not that hard to follow. Again, the symbols involved all compose nicely and are unambiguous. And frankly, you just don’t need something like that all that often (and when you do, there are usually other alternatives if you’re really put off by the symbols.
Someone mentioned the use of ")?)?" (in terms of error handling), I am quite put off by this, too. :P
Anyways, I will try to look for the code, it is somewhere in my comment history but I have left way too many comments, so no promises.
I would one million percent rather type (and read)
over something like But also even better is justI prefer ("if a, err := bar() {"), the same things you said applies here, too. I write a lot of Go and I can glance through it quickly, there is no cognitive overhead for me.
Edit: actually, it was someone else who said this: "Human brain has a funny way of learning how to turn off the noise and focus on what really matters.".
The difference is, there is no room for bugs with ?. Zero. None.
I have fixed (and frankly, caused) many bugs in golang code where people’s brains “turned off the noise” and filtered out the copypasta’d error handling, which overwrote the wrong variable name or didn’t actually bubble up the error or actually had subtly wrong logic in the conditional part which was obscured by the noise.
Frankly, learning to ignore that 80% of your code is redundant noise feels to me like a symptom of Stockholm syndrome more than anything else.
One symbol to replace three lines of identical boilerplate is no less explicit and dramatically clearer.
It's even nicer in Rust: there can be an "implicit" conversion between the error raised by foo and bar:
If FooError can be created from BarError, the compiler will insert the conversion call and errors bubbles up nicely.> How come is it in demand?
It's a curly-brace language with some solid decisions (e.g. default immutability) that produces static binaries and without a need for a virtual machine, while making some guarantees that eliminate a swathe of possible bug types at compile time.
As others note, the symbol soup is something you learn to read fluently and isn't worth getting hung up on.
Basically it occupies something of a sweet spot in the power/useability/safety space and got a decent PR shove by coming out of Mozilla back when they were the cool kids. I like it a lot. YMMV.
<'_> is one of the most basic symbols in Rust. Reading that is almost like reading the letter 'a after just some very modest amount of time with the language.
> How come is it in demand?
Because there's a lot more to the language than just those not-really-unfamiliar symbols
Its not required. There's a high chance you can avoid writing explicit lifetimes, it's just another tool for you to use
Rust's design is designed to be more in the mentality of if it compiles that it is good enough, leaving less for runtime issues to occur unexpected, dictated by type and memory safety. So, it requires more type info (unless you use unidiomatic unsafe code) and talking with borrow checker. But, once you internalize its type system and borrow checker, it pays off if you care about compiler driven development (instead of dealing with errors in runtime).
> How come it is in demand?
Because it's a complicated language for building extremely low level things, when you have no other choice. IMO it's not the right tool for high level stuff (even though it does have some stuff which higher level languages should probably borrow).
The only other language that directly competes with Rust IMO is C++, which is equally full of symbol soup.
> IMO it's not the right tool for high level stuff
I thought that for a long time. But as time passes and I spend more time in languages like Typescript (Semi-Type Script more accurately) and Swift the more I yearn for Rust.
It is not the right tool for scripting, true.
Yeah I feel that, not the entire language but, many of its choices, like error handling, sum types (with exhaustive enum matching) especially when writing in python.
I find it fine for high-level stuff as well. I never get complaining about syntax (in any language).
It's more batteries included and the packaging ecosystem story is better than alternatives. Certain safety guarantees are a nice to have.
If you just want a better c/c++ afaik that's zig, but I have no experience with it
An aside question I have is what’s the best beginner Rust book out there that is up to date?
I been learning Rust off and on and I have a more serious need to get up to speed with it but I’m unsure where it’s best to start in this way
In this order:
1. The Rust Book (Free) - https://doc.rust-lang.org/book/
2. Rust by Example (Free) - https://doc.rust-lang.org/rust-by-example/
3. Rust Atomics and Locks - https://marabos.nl/atomics/
4. Rust in Action - https://www.rustinaction.com/
5. Rust for Rustaceans - https://rust-for-rustaceans.com/
Also Jon Gjengset's channel is immensely valuable: https://www.youtube.com/c/JonGjengset
What do you think about Rust for Rustaceans? I read it and there are very niche and useful information there about Rust that I didn't see anywhere. It's a solid book but for a book about programming there are so few real code examples that it can come off dry. I just bought Rust atomic and locks and it seems exercise based, so I'm excited to finish it. The first chapter seems promising
As title implies, Rust for Rustaceans is not for those that are just starting with the language.
You are right about it not being a beginner friendly book. Hence why I placed it lower in the order of books to study.
Yeah Rust atomics and locks is essential if you truly want to understand low-level concurrency. But you might have to also refer to the C++ std::atomics reference [1] to get a complete idea. It took me a while to grasp those concepts.
[1]: https://en.cppreference.com/w/cpp/atomic/atomic
I have a hard copy of Programming Rust by Jim Blandy et al would that slot in nicely anywhere here?
Programming Rust is the best beginner Rust programming book in my opinion, followed by the official book. It has more detail and better examples.
"Programming Rust" by Jim Blandy et al was the book that really helped me to understand why many of the design decisions behind the implementation of Rust were made.
I found it more approachable than some of the other Rust books and highly recommend it as a first Rust book.
Unfortunately, I haven't read Programming Rust. The list includes just the books I used to learn Rust. But will definitely give Blandy's book a read. Thanks for the recommendation!
The Rust Programming Language does a great job imho. It got me up to speed by reading it before bed for a month. I’d never written C/C++ before, just a lot of Python. It starts out really simply by explaining the type system and the borrow checker. Take it from there and do a couple of side projects, I’d say.
Write an `iced` app, is my suggestion. You'll learn some of the best of what Rust has to offer
C/C++ are two very different languages.
Zig seems to follow the C tradition, and Rust C++.
Why do people say Rust follows the tradition of C++? Rust follows very different design decisions than C++ like a different approach to backwards compatibility, it does not tack on one feature on top of another, it is memory safe etc that are very different from C++. If you are just comparing the size of language, there are other complex languages out there like D, Ada etc
> Why do people say Rust follows the tradition of C++?
They mean the domain that Rust is in.
Before Rust there was only C or C++ for real time programming. C++ was an experiment (wildly successful IMO when I left it in 2001) trying to address the shortcomings of C. It turned out that too much of everything was in C++, long compile times, a manual several inches thick, huge executables. Some experiments turned out not to be a good idea (exceptions, multiple inheritance, inheritance from concrete classes....)
Rust is a successor in that sense. It draws on the lessons of C++ and functional programming.
I hope I live long enough to see the next language in this sequence that learns form the mistakes of Rust (there are a few, and it will take some more years to find them all)
> the packaging ecosystem story
I love Rust, I am a devotee and an advocate.
But the packaging system, more importantly the lack of a comprehensive system crate, is one of the greatest weaknesses of Rust.
A simple programme can pull in hundreds of crates from goodness knows where and by Dog knows who, for all sorts of uncertainties.
There are work arounds, but they eat up time that could be used far more productively
Zig is not yet stable enough to base a long-term project around, unless something's changed very recently.
If you really only want a better C/C++, use C++ and amp up your use of safer types (or consider D).
Now try BQN (Advent of Code 2020 Problem 2):
Or Brainfuck https://github.com/nicuveo/advent-of-code/blob/main/2022/bra...
Lifetimes and annotations only look like symbol soup initially (when you have little to no experience in Rust). The more proficient you become in Rust more you end up ignoring it completely. Sort of like ads you see (or don't) in Search. Human brain has a funny way of learning how to turn off the noise and focus on what really matters.
You become used reading this. Typing it is such a pain; I mean real pain like muscle pains.
I developed some muscles I didn't know I had.
Rust's syntax isn't gonna win any awards, but it looks sufficiently like C++ to hide that Rust is essentially an ML variant with linear types.
It was designed to be used with syntax highlighting and LSPs. The highlighting makes it pretty easy to read for me. Although there are some arcane generics with lifetimes that can be indecipherable in some libraries.
What is this constant push in software development to dumb everything down to the lowest common denominator?
I don't see it in other fields, at all.
I have to say I have no trouble seeing it absolutely everywhere.
Off the bat: I like Rust. I'm still very much a novice with it, but I enjoy it.
But almost the entirety of Computer Science is based on abstractions because they're helpful to "dumb down" some details that aren't super-important for our day-to-day work. E.g., writing TCP protocols directly is Assembly would be too fine-grained detail for most people's usual work, and using some existing abstraction is "good enough" virtually all of the time (even though we might be able to optimize things for our use-cases if we did drop down to that level)
There exists programming work where fiddling with lifetimes is just too fiddly to be worthwhile (e.g., web development, probably is more than fine using a good ol' garbage collected language). This isn't about "dumbing down" anything, it's about refocusing on what's important for the job you're doing.
> dumb everything down to the lowest common denominator
What do you mean?
Wait til you learn about APL...
Seriously though, I immediately parse it as "generic bounds containing the erased lifetime, close parenthesis". It's not a big deal.
And of all the critics one might have on Rust (or any other programming language), "too much symbols" appear like a weak one.
[dead]
Kind of surprised that this book could be published by O'Reilly and also freely available online? Seems unusually generous.
Possibly a sign of confidence. After browsing this for a few minutes, I'm very convinced of its quality and will probably buy it.
Wouldn't have happened with a book with just sample pages.
Why buy it if it’s completely free which is implied by your post?
To support the author. And as a way of saying thank you.
The last 2 books I’ve bought (ostep and nand2tetris) are available online. Hard copies are nice and personally seeing it on my desk gives more more motivation to finish them.
Because we all know what happens if we're not the customer.
I have this; I bought it because I want to reward the author for producing a quality work, and because I want to encourage the publishers to produce other works that would appeal to me.
I also happen to like physical texts so I bought the paperback but I have this and the digital edition. The latter is convenient for when I am travelling and appropriately formatted for an eReader (not just the raw html from these pages).
Because the people want to show appreciation for the good work the author has done?
True for digital copies, I've never yet bought one of those.
I have no trouble paying for physical books though.
Because I have written a book and thus know how much work it is to write even a mediocre one.
Also as a way to increase my motivation to read it.
Plus I have money. This book costs about as much as a good bottle of wine or a bad bottle of whiskey.
> Plus I have money. This book costs about as much as a good bottle of wine or a bad bottle of whiskey.
Exactly.
A few years ago I did a really aggressive weeding out of my bookshelves as things were getting far too cluttered. In the process I threw out what must have been - at cover price - several thousand pounds worth of IT related books.
On the resale market they were all too stale to have any value (though I did manage to give a handful away to friends). In one way it was a bit painful, but those few thousand pounds worth of books has given me a huge (financial) return on that investment!
Cheap at the cost of a good bottle of wine ... for the foundations of a career!
The book isn’t free, its contents are published online by the author. Yes, nitpicking. But (1) I like a well formatted epub and (2) the author/publisher still hold copyright.
I want to read on Kindle or own the book.