Learning Rust and Lemmy

Welcome to week 31 of Reading Club for Rust’s “The Book” (“The Rust Programming Language”). “The Reading” Chapter 21: https://rust-book.cs.brown.edu/ch18-03-pattern-syntax.html (the special Brown University version with quizzes etc) The Twitch Stream Starting today within the hour @sorrybookbroke@sh.itjust.works twitch stream on this chapter: https://www.twitch.tv/deerfromsmoke https://www.youtube.com/watch?v=ou2c5J6FmsM&list=PL5HV8OVwY_F9gKodL2S31czb7UCwOAYJL (YouTube Playlist) Be sure to catch future streams (will/should be weekly: https://www.twitch.tv/deerfromsmoke)

4
0

- Today (monday september 23), at 18:00 UTC+2 - We'll be starting chapter 8, Common Collections: https://rust-book.cs.brown.edu/ch08-00-common-collections.html - twitch.com/Jayjader for the stream - vod link: https://youtu.be/41SQ0BsbcIA

11
0

# Intro Having read through the macros section of "The Book" (Chapter 19.6), I thought I would try to hack together a simple idea using macros as a way to get a proper feel for them. The chapter was a little light, and declarative macros (using `macro_rules!`), *which is what I'll be using below*, seemed like a potentially very nice feature of the language ... the sort of thing that really makes the language malleable. *Indeed, in poking around I've realised, perhaps naively, that macros are a pretty common tool for rust devs (or at least more common than I knew).* I'll rant for a bit first, which those new to rust macros may find interesting or informative (it's kinda a little tutorial) ... *to see the implementation, go to "Implementation (without using a macro)" heading and what follows below*. # Using a macro Well, "declarative macros" (with `macro_rules!`) were pretty useful I found and easy to get going with (such that it makes perfect sense that they're used more frequently than I thought). * It's basically pattern matching on arbitrary code and then emitting new code through a templating-like mechanism (pretty intuitive). * The type system and `rust-analyzer` `LSP` understand what you're emitting perfectly well in my experience. It really felt properly native to rust. ## The Elements of writing patterns with "Declarative macros" **Use `macro_rules!` to declare a new macro** Yep, it's also a macro! **Create a structure just like a `match expression`** * Except the pattern will match on the code provided to the new macro * ... And uses special syntax for matching on generic parts or fragments of the code * ... And it returns new code (not an expression or value). **Write a pattern as just rust code with "generic code fragment" elements** * You write the code you're going to match on, *but for the parts that you want to capture as they will vary from call to call*, you specify variables (or more technically, "metavariables"). * You can think of these as the "arguments" of the macro. As they're the parts that are operated on while the rest is literally just static text/code. * These variables *will have a name and a type*. * The name as prefixed with a dollar sign `$` like so: `$GENERIC_CODE`. * And it's type follows a colon as in ordinary rust: `$GENERIC_CODE:expr` * These types are actually syntax specifiers. They specify what part of rust syntax will appear in the fragment. * *Presumably,* they link right back into the rust parser and are part of how these macros integrate pretty seamlessly with the type system and borrow checker or compiler. * Here's a decent list from rust-by-example (you can get a full list in the [rust reference on macro "metavariables"](https://doc.rust-lang.org/reference/macros-by-example.html#metavariables)): * `block` * `expr` is used for expressions * `ident` is used for variable/function names * `item` * `literal` is used for literal constants * `pat` (pattern) * `path` * `stmt` (statement) * `tt` (token tree) * `ty` (type) * `vis` (visibility qualifier) *So a basic pattern* that matches on any `struct` while capturing the `struct`'s name, its only field's name, and its type would be: ```rust macro_rules! my_new_macro { ( struct $name:ident { $field:ident: $field_type:ty } ) } ``` Now, `$name`, `$field` and `$field_type` will be captured for any single-field `struct` (and, *presumably*, the validity of the syntax enforced by the "fragment specifiers"). **Capture any repeated patterns with `+` or `*`** * Yea, just like `regex` * Wrap the repeated pattern in `$( ... )` * Place whatever separating code that will occur between the repeats *after* the wrapping parentheses: * EG, a separating comma: `$( ... ),` * Place the repetition counter/operator after the separator: `$( ... ),+` ### Example *So, to capture multiple fields in a `struct`* (expanding from the example above): ```rust macro_rules! my_new_macro { ( struct $name:ident { $field:ident: $field_type:ty, $( $ff:ident : $ff_type: ty),* } ) } ``` * This will capture the first field and then any additional fields. * The way you use these repeats mirrors the way they're captured: they all get used in the same way and rust will simply repeat the new code for each repeated captured. ## Writing the emitted or new code **Use `=>` as with match expressions** * Actually, it's `=> { ... }`, IE with braces (not sure why) **Write the new emitted code** * All the new code is simply written between the braces * Captured "variables" or "metavariables" can be used just as they were captured: `$GENERIC_CODE`. * *Except types aren't needed here* * Captured repeats are expressed within wrapped parentheses just as they were captured: `$( ... ),*`, including the separator (which can be different from the one used in the capture). * The code inside the parentheses can differ from that captured (*that's the point after all*), but at least one of the variables from the captured fragment has to appear in the emitted fragment so that rust knows which set of repeats to use. * A useful feature here is that the repeats can be used multiple times, in different ways in different parts of the emitted code (the example at the end will demonstrate this). ### Example *For example*, we could convert the `struct` to an `enum` where each field became a variant with an enclosed value of the same type as the `struct`: ```rust macro_rules! my_new_macro { ( struct $name:ident { $field:ident: $field_type:ty, $( $ff:ident : $ff_type: ty),* } ) => { enum $name { $field($field_type), $( $ff($ff_type) ),* } } } ``` With the above macro defined ... this code ... ```rust my_new_macro! { struct Test { a: i32, b: String, c: Vec<String> } } ``` ... will emit this code ... ```rust enum Test { a(i32), b(String), c(Vec<String>) } ``` # Application: "The code" before making it more efficient with a macro *Basically ... a simple system for custom types to represent physical units.* ## The Concept (and a rant) A basic pattern I've sometimes implemented on my own (without bothering with dependencies that is) is creating some basic representation of physical units in the type system. Things like meters or centimetres and degrees or radians etc. If your code relies on such and performs conversions at any point, *it is way too easy to fuck up*, and therefore worth, IMO, creating some safety around. NASA provides an obvious warning. As does, IMO, common sense and experience: most scientists and physical engineers learn the importance of "dimensional analysis" of their calculations. In fact, it's the sort of thing that should arguably be built into any language that takes types seriously (like eg rust). I feel like there could be an argument that it'd be as reasonable as the numeric abstractions we've worked into programming?? At the bottom I'll link whatever crates I found for doing a better job of this in rust (one of which seemed particularly interesting). ## Implementation (without using a macro) The essential design is (again, this is basic): * A single type for a particular dimension (eg time or length) * Method(s) for converting between units of that dimension * *Ideally*, flags or constants of some sort for the units (thinking of enum variants here) * These could be methods too ```rust #[derive(Debug)] pub enum TimeUnits {s, ms, us, } #[derive(Debug)] pub struct Time { pub value: f64, pub unit: TimeUnits, } impl Time { pub fn new<T: Into<f64>>(value: T, unit: TimeUnits) -> Self { Self {value: value.into(), unit} } fn unit_conv_val(unit: &TimeUnits) -> f64 { match unit { TimeUnits::s => 1.0, TimeUnits::ms => 0.001, TimeUnits::us => 0.000001, } } fn conversion_factor(&self, unit_b: &TimeUnits) -> f64 { Self::unit_conv_val(&self.unit) / Self::unit_conv_val(unit_b) } pub fn convert(&self, unit: TimeUnits) -> Self { Self { value: (self.value * self.conversion_factor(&unit)), unit } } } ``` So, we've got: * An `enum` `TimeUnits` representing the various units of time we'll be using * A `struct` `Time` that will be any given `value` of "time" expressed in any given `unit` * With methods for converting from any units to any other unit, the heart of which being a `match expression` on the new unit that hardcodes the conversions (relative to base unit of seconds ... see the `conversion_factor()` method which generalises the conversion values). *Note:* I'm using `T: Into<f64>` for the `new()` method and `f64` for `Time.value` as that is the easiest way I know to accept either integers or floats as values. It works because `i32` (and most other numerics) can be converted lossless-ly to `f64`. *Obviously you can go further than this. But the essential point is that each unit needs to be a new type with all the desired functionality implemented manually or through some handy use of blanket trait implementations* # Defining a macro instead *For something pretty basic, the above is an annoying amount of boilerplate!!* May as well rely on a dependency!? Well, we can write the boilerplate once in a macro and then only provide the informative parts! In the case of the above, the only parts that matter are: * The name of the type/`struct` * The name of the units `enum` type we'll use (as they'll flag units throughout the codebase) * The names of the units we'll use and their value relative to the base unit. IE, for the above, we only need to write something like: ```rust struct Time { value: f64, unit: TimeUnits, s: 1.0, ms: 0.001, us: 0.000001 } ``` *Note: this isn't valid rust!* But that doesn't matter, so long as we can write a pattern that matches it and *emit* valid rust from the macro, it's all good! (Which means we can write our own little DSLs with native macros!!) To capture this, all we need are what we've already done above: capture the first two fields and their types, then capture the remaining "field names" and their values in a repeating pattern. ## Implementation of the macro **The pattern** ```rust macro_rules! unit_gen { ( struct $name:ident { $v:ident: f64, $u:ident: $u_enum:ident, $( $un:ident : $value:expr ),+ } ) } ``` * Note the repeating fragment doesn't provide a type for the field, but instead captures and expression `expr` after it, *despite being invalid rust*. **The Full Macro** ```rust macro_rules! unit_gen { ( struct $name:ident { $v:ident: f64, $u:ident: $u_enum:ident, $( $un:ident : $value:expr ),+ } ) => { #[derive(Debug)] pub struct $name { pub $v: f64, pub $u: $u_enum, } impl $name { fn unit_conv_val(unit: &$u_enum) -> f64 { match unit { $( $u_enum::$un => $value ),+ } } fn conversion_factor(&self, unit_b: &$u_enum) -> f64 { Self::unit_conv_val(&self.$u) / Self::unit_conv_val(unit_b) } pub fn convert(&self, unit: $u_enum) -> Self { Self { value: (self.value * self.conversion_factor(&unit)), unit } } } #[derive(Debug)] pub enum $u_enum { $( $un ),+ } } } ``` Note the repeating capture is used twice here in different ways. * The capture is: `$( $un:ident : $value:expr ),+` And in the emitted code: * It is used in the `unit_conv_val` method as: `$( $u_enum::$un => $value ),+` * Here the `ident` `$un` is being used as the variant of the `enum` that is defined later in the emitted code * Where `$u_enum` is also used without issue, as the name/type of the `enum`, despite not being part of the repeated capture but another variable captured outside of the repeated fragments. * It is then used in the definition of the variants of the enum: `$( $un ),+` * Here, only one of the captured variables is used, which is perfectly fine. ## Usage Now all of the boilerplate above is unnecessary, and we can just write: ```rust unit_gen!{ struct Time { value: f64, unit: TimeUnits, s: 1.0, ms: 0.001, us: 0.000001 } } ``` *Usage from `main.rs`:* ```rust use units::Time; use units::TimeUnits::{s, ms, us}; fn main() { let x = Time{value: 1.0, unit: s}; let y = x.convert(us); println!("{:?}", x); println!("{:?}", x); } ``` *Output:* ```rust Time { value: 1.0, unit: s } Time { value: 1000000.0, unit: us } ``` * Note how the `struct` and `enum` created by the emitted code is properly available from the module as though it were written manually or directly. * In fact, my LSP (`rust-analyzer`) was able to autocomplete these immediately once the macro was written and called. # Crates for unit systems I did a brief search for actual units systems and found the following ## `dimnesioned` **[`dimensioned` documentation](https://docs.rs/dimensioned/latest/dimensioned/index.html)** * Easily the most interesting to me (from my quick glance), as it seems to have created the most native and complete representation of physical units in the type system * It creates, through types, a 7-dimensional space, one for each SI base unit * This allows all possible units to be represented as a reduction to a point in this space. * EG, if the dimensions are `[seconds, meters, kgs, amperes, kelvins, moles, candelas]`, then the `Newton`, `m.kg / s^2` would be `[-2, 1, 1, 0, 0, 0, 0]`. * This allows all units to be mapped directly to this consistent representation (*interesting!!*), and all operations to then be done easily and systematically. Unfortunately, I'm not sure if the [repository](https://github.com/paholg/dimensioned) is still maintained. ## uom **[uom documentation](https://docs.rs/uom/latest/uom/)** * This might actually be good too, I just haven't looked into it much * It also seems to be currently maintained ## F# Interestingly, `F#` actually has a system built in! * See [learning documentation on `F#` here](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure) * Also this older (2008) [series of blogs on the feature here](https://learn.microsoft.com/en-us/archive/blogs/andrewkennedy/units-of-measure-in-f-part-one-introducing-units)

15
14
https://pony.social/@thephd/112818744298401332

The post mentions data or research on how rust usage in is resulting in fewer errors in comparison to C. Anyone aware of good sources for that?

10
8
https://cliffle.com/p/dangerust/

A supplement to typical tutorials that caters to C programmers interested in learning how to be unsafe upfront. Seems good from a quick skim. Also seems that the final lesson is that starting on the safe/happy path in rust doesn’t have to cost performance if you know what you’re doing.

8
0

Just a quick riff/hack on whether it'd be hard to make a `collect()` method that "collected" into a `Vec` without needing any turbofish (see, if you're interested, my [prior post on the `turbofish`](https://lemmy.ml/post/17715376). *Some grasp of traits and iteration is required to comfortably get this ... though it might be a fun dive even if you're not* ### Background on `collect` The implementation of `collect` is: ```rust fn collect<B: FromIterator<Self::Item>>(self) -> B where Self: Sized, { FromIterator::from_iter(self) } ``` The generic type `B` is bound by `FromIterator` which basically enables a type to be constructed from an `Iterator`. In other words, `collect()` returns *any* type that can be built from an interator. EG, `Vec`. The reason the `turbofish` comes about is that, as I said above, it returns "*any* type" that can be built from an iterator. So when we run something like: ```rust let z = [1i32, 2, 3].into_iter().collect(); ``` ... we have a problem ... rust, or the `collect()` method has no idea what type we're building/constructing. More specifically, looking at the code for `collect`, in the call of `FromIterator::form_iter(self)`, which is calling the method on the trait directly, rust has no way to determine *which implementation* of the trait to use. The one on `Vec` or `HashMap` or `String` etc?? Thus, the `turbofish` syntax specifies the generic type `B` which (somehow through type inference???) then determines which implementation to use. ```rust let z = [1i32, 2, 3].into_iter().collect::<Vec<_>>(); ``` *IE: Use the implementation on `Vec`!* ### Why not just use `Vec`? I figure `Vec` is used so often as the type for collecting an `Iterator` that it could be nice to have a convenient method. The docs even hint at this by suggesting that calling the `FromIterator::from_iter()` method directly from the desired type (eg `Vec`) can be more readable (see [`FromIterator` docs](https://doc.rust-lang.org/core/iter/trait.FromIterator.html)). *EG ... using `collect`*: ```rust let d = [1i32, 2, 3]; let x = d.iter().map(|x| x + 100).collect::<Vec<_>>(); ``` *Using `Vec::from_iter()`* ```rust let y = Vec::from_iter(d.iter().map(|x| x + 100)); ``` As `Vec` is always in the prelude (IE, it's always available), using `from_iter` clearly seems like a nicer option here. *But you lose method chaining!* So ... how about a method on `Iterator`, like `collect` but for `Vec` specifically? How would you make that and is it hard?? ### Making `collect_vec()` *It's not hard actually* * Define a trait, `CollectVec` that defines a method `collect_vec` which returns `Vec<Self::Item>` * Make this a "sub-trait" of `Iterator` (or, make `Iterator` the "supertrait") so that the `Iterator::collect()` method is always available * Implement `CollectVec` for all types that implement `Iterator` by just calling `self.collect()` ... *the type inference will take care of the rest, because it's clear that a `Vec` will be used*. ```rust trait CollectVec: Iterator { fn collect_vec(self) -> Vec<Self::Item>; } impl<I: Iterator> CollectVec for I { fn collect_vec(self) -> Vec<Self::Item> { self.collect() } } ``` With this you can then do the following: ```rust let d = [1i32, 2, 3]; let d2 = d.iter().map(|x| x + 1).collect_vec(); ``` Don't know about you, but implementing such methods for the common collection types would suit me just fine ... that turbofish is a pain to write ... and AFAICT this isn't inconsistent with rust's style/design. And it's super easy to implement ... the type system handles this issue very well.

3
2
https://doc.rust-lang.org/stable/std/f32/consts/index.html

I hadn't thought about this until now. Handy. Of course there's the [`f64` equivalent](https://doc.rust-lang.org/stable/std/f64/consts/index.html): `std::f64::consts`

8
0
https://doc.rust-lang.org/std/thread/fn.spawn.html

*This pertains to Ch 16.03 of The Book, specifically `Arc` in multithreaded programs* I was just looking at the signature for `thread::spawn` (documentation linked to by post URL) wondering if and how the requirement for a thread-safe smart pointer is enforced by the type system. In short, how is the use of `Arc` necessitated by the type system?? For the signature, you get this: ```rust pub fn spawn<F, T>(f: F) -> JoinHandle<T> where F: FnOnce() -> T + Send + 'static, T: Send + 'static, ``` Where the parameter `f` is bound by ` F: FnOnce() -> T + Send + 'static`. And ... I'm not entirely sure how I should think about this. Obviously, `Send` and `'static` here are related to my question, where *in some way* the closure must be thread-safe (through the `Send` trait) and also have a whole-life-of-the-program lifetime (through the `'static` lifetime). Therefore, *in some way*, something like `Rc` would be invalid but `Arc` would be. **But how exactly?** 1. Are the bounds on the return type of the function/closure, which then sort of back propagate onto the input parameters or captured values of the function/closure? 1. Or are these somehow properties of the function itself? 1. And why is `T` separately bound by `Send + 'static` when they are already present in the bounds on `F`? My best guess is that the bounds on `F` are best parsed as ... ```rust F: ( FnOnce() -> T ) + Send + 'static T: Send + 'static ``` IE, Everything separated by a `+` is unitary, and, therefore, `FnOnce() -> T` is a single bound and `Send` another separate bound. But I'm unsure about that, haven't read that anywhere, and am not really sure how to understand how exactly a function *can have* `Send` or `'static` without some logic linking that directly to its input parameters? Thoughts?

5
4

I'll be clear, quite embarrassingly I bit my tongue hard last night and haven't been talking right all day. Hurts to talk, hurts to eat, and worst of all hot tea is undrinkable. How will I live. Now I know exactly what it feels like to be soldier wounded in combat. Will resume next week in full force. In the meantime however please feel free to read ahead. Or, alternatively, try out a few leetcode\advent of code questions. This what I'll be doing tonight.

24
6
https://turbo.fish/

The [`about` section](https://turbo.fish/about) of the linked page has links and a brief explanation of the story. In my own words ... ### Description of the Turbo-fish syntax * Whenever a generic type (see ch 10 of The Book) is involved in calling a function/method or constructing/handling a struct/enum, you may need to specify that concrete type for that generic. * See [this handy blog post on the turbofish that lists when it's necessary](https://matematikaadit.github.io/posts/rust-turbofish.html) * This type is provided with the `turbo fish` syntax: `::<>` ... where the type goes between the angle brackets. * EG: ```rust let v = Vec::new(); let v2 = Vec::<i32>::new() ``` * The elements of `v` have an undefined type, which rust will infer once an element is pushed into it. But `v2` has a defined element type, `i32`, defined using the `turbo fish`. --- ### The Story * This syntax wasn't always liked, and the double colons (`::`) thought redundant. * But it stuck * And was given the name "turbo-fish" by Anna Harren (u/deadstone, Reddit) ... who sadly passed away in 2021. * It turns out that the double colons are pretty vital to preventing ambiguity. * This is enshrined in the [**Bastion of the Turbofish**](https://github.com/rust-lang/rust/blob/43192ca3d72ed0ca42ba913137585219ba0a691f/src/test/ui/parser/bastion-of-the-turbofish.rs) which stands as a memorial to Anna Harren ... * a test in the language's test suite that ensures that the double-colons syntax isn't removed by directly using the ambiguous syntax that'd arise without it. * See if you can understand the test (it took me a while! ... [this HN post might help](https://news.ycombinator.com/item?id=27155091)): ```rust let (the, guardian, stands, resolute) = ("the", "Turbofish", "remains", "undefeated"); let _: (bool, bool) = (the<guardian, stands>(resolute)); ``` *hint: what are angle brackets normally used for and how are `bool` types related to that?*

11
2
github.com

Nice and handy reference with explanations and examples.

7
0

You've gotta be familiar with `Traits` to try to work this out. ::: spoiler Just in case you want to try to work it out your self first Gotta say, after hearing that rust is not an OOP/Class-inheritance language, and is strongly and explicitly typed, the `Deref` trait feels like a helluva drug! Obviously it's not the same thing, but working this out definitely had me making a couple of double takes. Somewhat awkwardly, I worked it out through the standard lib docs before reading ch 15 of the book (it's more fun this way!). And for those who want a quick answer: * Read the [`Deref` docs, especially the `deref coercion` part](https://dev-doc.rust-lang.org/stable/std/ops/trait.Deref.html#deref-coercion) * This allows a variable of a particular type to be *implicitly* substituted with another variable of a different type. * It happens any time a reference is passed in/out of a function, including `self` in method calls. * And obviously requires that `Deref` be implemented. * So `sort()` isn't implemented on `Vec`, it's implemented on the `slice` type (`[T]`). * But `Vec` implements `Deref`, substituting `[T]` for `Vec<T>` in all function/method calls. * Which means `Vec` gets all of the methods implemented on `[T]` ... *almost like `Vec` is a subclass of `[T]`*! * And yea, OOP people want to abuse this ([see, eg, rust-unofficial on anti-patterns](https://rust-unofficial.github.io/patterns/anti_patterns/deref.html)) :::

6
0

# What? I will be holding the fifteenth of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). Last time we began chapter 7 (Managing Growing Projects with Packages, Crates, and Modules), and read up through section 7.3 (Paths for Referring to an item in the Module Tree). This time we will start at section 7.4 (Bringing Paths Into Scope with the use Keyword). Previous session details and recording can be found in the following lemmy post: https://jlai.lu/post/8006138 # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+2 (aka 6pm Central European Time) on Monday (2023-07-01). If you were present for a previous session, then basically the same time-of-day and day-of-week as that one was. **EDIT: here's the recording: https://youtu.be/RI4D62MVvCA** **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will be locally recorded, and uploaded afterwards to youtube (for now as well). I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup`, `cargo`, and `clippy`) - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the book, both reading aloud the literal text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

7
1
https://doc.rust-lang.org/std/marker/trait.Copy.html

Continuing on from Chs 5 & 6 of "The Book" (see "Reading Club" post [here](https://lemmy.ml/post/17112524)), I don't think the `Copy` and `Clone` traits were quite given sufficient coverage. So I thought I'd post my understanding here. ### Tl;Dr | Copy | Clone | |------ |------- | | Implicit | Explicit (`v.clone()`)| | Simple (`memcpy`) | Arbitrary | | "cheap"/quick | Potentially expensive | | Simple types | Any type | ### Derivable Traits * These are traits which have a standard implementation that can be freely and easily applied to `structs` and `enums` (IE, custom types). * The ones available in the standard library are listed in [Appendix C of The Book](https://rust-book.cs.brown.edu/appendix-03-derivable-traits.html#debug-for-programmer-output). Other libraries/crates can apparently implement them too (though I don't know of any). * They are part of and use the `Attributes` syntax (see [Documentation in the Rust Reference here](https://doc.rust-lang.org/reference/attributes.html)): `#[ATTRIBUTE]`. * To derive a trait we write `#[derive(TRAIT1, TRAIT2, ...)]` above our type declaration ```rust #[derive(Copy, Clone)] struct Copyable { field: i32, } #[derive(Clone)] struct OnlyClonable { field: i32, } ``` ### The Three Step Ladder * The two traits, `Clone` and `Copy`, are about providing *opt-in* options for custom types around what "*ownership semantics*" they obey. * **"move semantics"**: are what we know for most types and have learnt about in ch 4. There is no copying, only the moving of ownership from one stack to another or the use of references and the "borrow checker" that verifies safety. * **"Copy semantics"**: are what basic types like `i32` enjoy. No ownership movements. Instead, these variables get implicitly copied, because they're simple and copying involves the same work involved in passing a memory address around. The RFC for these traits puts it nicely ... *From [RFC 0019 - Opt in built-in traits document on the Copy Trait](https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md#controlling-copy-vs-move-with-the-copy-trait)* > Effectively, there is a three step ladder for types: > > * If you do nothing, your type is linear, meaning that it moves from place to place and can never be copied in any way. (We need a better name for that.) > * If you implement Clone, your type is cloneable, meaning that it moves from place to place, but it can be explicitly cloned. This is suitable for cases where copying is expensive. > * If you implement Copy, your type is copyable, meaning that it is just copied by default without the need for an explicit clone. This is suitable for small bits of data like ints or points. > What is nice about this change is that when a type is defined, the user makes an explicit choice between these three options. *IE, "move semantics" are the default, "copy semantics" can be adopted, or clone for the more complicated data types or for where it is desired for duplication to be explicit.* * Note that `Clone` is a `supertrait` of `Copy`, meaning that we have to derive `Clone` if we want to derive `Copy`, but can derive `Clone` on its own. ```rust struct Movable { field: i32 } #[derive(Clone)] struct OnlyClonable { field: i32, } #[derive(Copy, Clone)] struct Copyable { field: i32, } ``` ### Example *Demonstrate how a struct with `Copy` obeys "copy semantics" and gets copied implicitly instead of "moved"* * Declare `structs`, with derived traits, and define a basic function for taking ownership ```rust fn check_if_copied<T: Clone>(x: T) -> T { println!("address: {:p} (from inner owning function)", &x); x } #[derive(Clone)] struct OnlyClonable { field: i32, } #[derive(Copy, Clone)] struct Copyable { field: i32, } ``` * Instantiate variables of both `structs`, `cl` that has `Clone` and `cp` that has `Copy`. * `cl` is moved into `check_if_copied` and so is no longer live or usable afterward. * `cp` is not moved into `check_if_copied` and lives beyond the call of `check_if_copied`. ```rust let cl = OnlyClonable{field: 0}; let cp = Copyable{field: 1}; // OnlyClonable type obeys "move semantics" check_if_copied(cl); // cl gets moved in as it's not copyable // COMPILER ERROR. Can't do this! As moved into `report_if_copied`! println!("address: {:p}", &cl); // Copyable obeys "copy semantics" check_if_copied(cp); // cp is implicitly copied here! // Can! as not moved but copied println!("address: {:p}", &cp); ``` *Demonstrate the same but with mutation* ```rust let mut mcp = Copyable{field: 1}; let mcp2 = check_if_copied(mcp); // as mcp was implicitly copied, mcp2 is a new object mcp.field += 100; // values will be different, one was mutated and has kept the data from before the mutation println!("mcp field: {}", mcp.field); println!("mcp2 field: {}", mcp2.field); ``` *prints ...* ``` mcp field: 101 mcp2 field: 1 ``` ### Application and Limitations #### Copy * `Copy` is available only on types whose elements also have `Copy`. * Such elements then need to be the numeric types (`i32`, `f64` etc), `bool` and `char`. So custom types that contain only basic data types. ```rust #[derive(Copy, Clone)] struct Copyable { field: i32, } ``` * Any field with a non-copyable type such as `String` or `Vec` cannot be made Copyable ```rust // Copy cannot be derived as `f2: String` does not implement Copy #[derive(Copy, Clone)] struct NotCopyable2 { field: i32, f2: String } ``` * But custom types that have the `Copy` trait as fields work fine, like `Copyable` from above as a field: ```rust #[derive(Copy, Clone)] struct Copyable2 { field: i32, more: Copyable } ``` * Beyond this, `Copy` is not overloadable and can't be implemented in rust (without using `unsafe` presumably). It's really just a primitive of the language it seems (see [source code for the Copy trait](https://doc.rust-lang.org/src/core/marker.rs.html#403)). #### Clone * Like `Copy`, `Clone` relies on the `struct's` fields also implementing `Clone`. * A number of standard library types have implemented `Clone` (see [list of implementors in the documentation](https://doc.rust-lang.org/std/clone/trait.Clone.html#implementors)), including the fundamental collections you'll find in chapter 8 of The Book: `String`, `Vec`, `HashMaps` and also `arrays`. * Thus the code below, which involves a more complex `Struct` with fields that are a `String`, `array` and `Vec`, compiles just fine. * With the `clone()` method, `Clonable` is now able to be duplicated allowing the original to be usable after being passed in to `check_if_copied()`. ```rust #[derive(Clone)] struct Clonable { name: String, values: [f64; 3], data: Vec<i32> } let clonable = Clonable{ name: "Sam".to_string(), values: [1.0, 2.0, 3.0], data: vec![111, 222] }; // clonable is duplicated with the `.clone()` method check_if_copied(clonable.clone()); // original still usable as it was never moved println!("Name; {}", clonable.name); ``` * But, unlike `Copy`, is overloadable, which means you can implemented `Clone` for your custom types however you want if necessary. * This would be jumping ahead a bit to `Traits`, but we could implement `Clone` for our `struct` above ourselves with something like the below: ```rust struct Clonable { name: String, values: [f64; 3], data: Vec<i32> } // Just use each field's `.clone()` implementation, much like the default would do impl Clone for Clonable { fn clone(&self) -> Self { Self { name: self.name.clone(), values: self.values.clone(), data: self.data.clone() } } } ``` * Or we could see how `Clone` is implemented for `Option`: ```rust impl<T> Clone for Option<T> where T: Clone, { fn clone(&self) -> Self { match self { Some(x) => Some(x.clone()), None => None, } } } ``` * Basically relies on the implementation of `Clone` for the inner value inside `Some`. Note the `where clause` that limits this to `Option` variables that contain values that have the `Clone` trait. ### Deep or Shallow Duplication * In the case of `Copy`, duplication should always be "deep". * Which isn't saying much due to the simplicity of the types that can implement `Copy`. * In the case of `Clone` ... **it depends!** * As the implementations of `Clone` on the fields of a custom `struct`/`enum` are relied on, whether the duplication is deep or shallow depends entirely on those implementations. * As stated in the `RFC` quoted above, `Clone` is for complex data structures whose duplication is not trivial such that compromises around performance and duplication depth may need to be made. * A clue can be discerned from the signature of the implementation. For `Option`, above, the inner value was restricted to also having implemented `Clone`, as the value's `.clone()` method was relied on. Therefore, `Option`'s is deep. * Similarly, the `Clone` implementation for `Vec` has the same restriction on its elements: `impl<T, A> Clone for Vec<T, A> where T: Clone,` (see [source code](https://doc.rust-lang.org/src/alloc/vec/mod.rs.html#2834)), indicating that its implementation is at least one level deep. --- Overall, this seemed a fundamental part of the language, and I found it weird that The Book didn't address it more specifically. There's nothing really surprising or difficult here, but the relative roles of `Clone` and `Copy`, or the "three step ladder" are important to appreciate I think.

4
0

Relevant for [@sorrybookbroke@sh.itjust.works](https://sh.itjust.works/u/sorrybookbroke) 's next stream next week as they're hitting smart pointers. cross-posted from: https://programming.dev/post/16059115 > Found this on Mastodon https://fosstodon.org/@dpom/112681955888465502 , and it is a very nice overview of the containers and their layout.

17
2

# What? I will be holding the fourteenth of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). Last time we completed chapter 6 (enums & pattern matching). This time we will begin chapter 7 (Managing Growing Projects with Packages, Crates, and Modules). Previous session details and recording can be found in the following lemmy post: https://jlai.lu/post/7773753 # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+2 (aka 6pm Central European Time) on this day (2023-06-24). If you were present for a previous session, then basically the same time-of-day and day-of-week as that one was. **Here's the recording: https://youtu.be/pUqVmPRLhNE** **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the book, both reading aloud the literal text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

7
2
https://rust-book.cs.brown.edu/ch06-04-inventory.html

After Chs 5 and 6 (see [the reading club post here](https://lemmy.ml/post/17112524)), we get a capstone quiz that covers ownership along with `struts` and `enums`. So, lets do the quiz together! *If you've done it already, revisiting might still be very instructive!* I certainly thought these questions were useful "revision". --- I'll post a comment for each question with the answer, along with my own personal notes (and quotes from The Book if helpful), behind spoiler tags. Feel free to try to answer in a comment before checking (if you dare). But the main point is to understand the point the question is making, so share any confusions/difficulties too, and of course any corrections of my comments/notes!.

5
6
https://rust-book.cs.brown.edu/ch05-00-structs.html

Finally, we can make our own types (or data structures)!! --- *This is supplementary/separate from the Twitch Streams (see sidebar for links), intended for discussion here on lemmy.* *The idea being, now that both twitch streams have read Chapters 5 and 6, we can have a discussion here and those from the twitch streams can have a retrospective or re-cap on the topic.* *This will be a regular occurrence for each discrete set of topics coming out of The Book as the twitch streams cover them* --- With Ch 4 on the borrow checker out of the way, chapters 5 & 6 feel like the "inflection point" ... the point where we're ready to actually start programming in rust. Custom types, data structures, objects with methods, pattern matching, and even dipping into rust's traits system and it's *quasi* answer to class inheritance. If you're comfortable enough with the borrow checker, you can really start to program with rust now! --- I personally didn't think this content was difficult, though it prompts some interesting points and topics (which I'll mention in my own comment below). * *Any thoughts, difficulties or confusions?* * *Any quizzes stump you?* * *Any major tips or rules of thumb you've taken away or generally have about using `structs` and `enums`?*

5
8
github.com

cross-posted from: https://lemmy.ml/post/17090253 > cross-posted from: https://lemmy.ml/post/17090149 > > > Hi! I've created a CLI tool for downloading Rust web books (like The Rust Programming Language) as EPUB, so that you can easily read them on your e-book reader. The tool is heavily based on [this gist](https://gist.github.com/peterbartha/54708ae739478a45b52612311d49717c) and a lot of proompting. > > > > Check it out here: https://github.com/mawkler/rust-book-to-epub

13
1

# What? I will be holding the thirteenth of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). Last time we started chapter 6 (enums & pattern matching). We read through 6.1 and learned how to define `enum` variants in tuple or struct form. We also learned about the `Option<T>` enum that Rust provides us with. This time we'll begin section 6.2 and learn about the `match` control flow construct. Previous session details and recording can be found in the following lemmy post: https://jlai.lu/post/7532130 # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+2 (aka 6pm Central European Time) on Monday (2023-06-17). If you were present for a previous session, then basically the same time-of-day and day-of-week as that one was. **EDIT: here's the recording https://youtu.be/W1fjxCwtwfM** **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the book, both reading aloud the literal text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

20
3

# What? I will be holding the twelfth of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). Last time we wrapped up chapter 5 (structs). This session we'll be learning about `enum`s by starting chapter 6. Previous session details and recording can be found in the following lemmy post: https://jlai.lu/post/7413233 # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+2 (aka 6pm Central European Time) on Monday (2023-06-10). If you were present for a previous session, then basically the same time-of-day and day-of-week as that one was. **EDIT: here's the recording https://youtu.be/eRMxhaJIOAg** **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the book, both reading aloud the literal text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

10
2

Stable internet connection re-acquired! To avoid waiting another full week, I'll be hosting the session today (approximately 6-7 hours after this post is created). # What? I will be holding the eleventh of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). Last time, the book guided us through An Example Program Using Structs (section 2 of chapter 5). Today we'll be tackling the following section, "The Method Syntax" (5.3). Previous session details and recording can be found in the following lemmy post: https://jlai.lu/post/6871662 # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+2 (aka 6pm Central European Time) on Tuesday (2023-06-04). If you were present for a previous session, then basically the same time-of-day ~~and day-of-week~~ as that one was. Exceptionally, today is not the same day-of-week as previously. Recording of the session: https://youtu.be/wBYdDbADFLU **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the book, both reading aloud the literal text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

8
1
https://users.rust-lang.org/t/perpetual-n00b-struggling-with-ownership-again/46920/10

A nice comment in a forum thread (extracted below, but also see the shorter more facetious version below that) about references and their lifetimes in structs. [Here is a link to the full thread over on users.rust-lang.org](https://users.rust-lang.org/t/perpetual-n00b-struggling-with-ownership-again/46920/1) I feel like I needed to hear or read this, and I feel like this sort of clarification is not put front and centre enough in rust learning material (as others in the thread say too). "The Book" certainly doesn't seem interested in clarifying perspectives like this. --- ### The Comment Other languages use term "reference" for storing things "by reference" or just referencing any object anywhere in general. It's not like that in Rust. What Rust calls "reference" is a much more specific thing, that is no so general-purpose. It has a narrower, restrictive usage. Rust references are more like read-only or write-exclusive locks. They make their target unmovable and immutable for entire duration of their existence. They can't exist on their own, only as a counterpart of an owned value. References in structs also make the whole struct itself temporary, and everything that touches that struct becomes temporary and tied to the scope of the borrowed value that started it. If these restrictions (that cause you fight with the borrow checker) aren't what you want to achieve, then you don't want temporary references. 99% of the time when you need to store something "by reference", `Box` (or `Arc` or `String` or `PathBuf` or `Vec` or some other owned type) is the right answer. Note that `&T` and `Box<T>` have identical representation in memory — a pointer. They differ by ownership. ### In Short *From [here](https://users.rust-lang.org/t/perpetual-n00b-struggling-with-ownership-again/46920/4)* You're not allowed to use references in structs until you think Rust is easy. They're the evil-hardmode of Rust that will ruin your day. 😉 Use Box or Arc to store things in structs "by reference". Temporary borrows don't do what you think they do.

17
12

Sorry y'all, I don't have access to a decent internet connection for the time being.

9
0
https://rust-book.cs.brown.edu/ch04-00-understanding-ownership.html

*This is supplementary/separate from the Twitch Streams (see sidebar for links), intended for discussion here on lemmy.* *The idea being, now that both twitch streams have read Chapter 4, we can have a discussion here and those from the twitch streams can have a retrospective or re-cap on the topic.* *This will be a regular occurrence for each discrete set of topics coming out of The Book as the twitch streams cover them* --- Ownership and the borrow checker are obviously a fundamental and unique topic to rust, so it's well worth getting a good grounding in AFAICT. 1. *Anyone up to trying to summarise or explain ownership/borrow-checker in rust?* * it can be a good exercise to test your understanding and get feedback/clarification from others ... as well as probably a good way to teach others 1. *Any persistent gripes, difficulties or confusions?* 1. *Any of the quizzes from The Book stump you?* 1. *Any hard learnt lessons? Or tried and true tips?*

7
6

# What? I will be holding the tenth of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). Last time we covered defining and instantiating structs with section 1 of chapter 5, "Using Structs to Structure Related Data". We'll be continuing with section 2, where we'll be writing some code! Previous session details and recording can be found in the following lemmy post: https://jlai.lu/post/6703544 # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+2 (aka 6pm Central European Time) on Monday (2023-05-20). If you were present for a previous session, then basically the same time-of-day and day-of-week as that one was. **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). **EDIT**: here's the recording https://youtu.be/s0U7KBXxL8g I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the book, both reading aloud the literal text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

11
1

We've got two parallel streams going here. One is up to chapter 10 on Traits and the other on chapter 5 on Structs & Enums. * How are we feeling about Rust the language? * Any persistent confusions or difficulties? * Favourite features or success stories? * How are we finding "The Book" in general? * *Personally, I think it's good but not great and am definitely reaching out for other learning experiences or materials, lately finding myself going through the [Std Lib Docs](https://doc.rust-lang.org/std/index.html) a bit* * *[Andy Balaam's Rust Tutorial Series](https://diode.zone/w/p/xesbWmNanEHNBfJCZFQRUm) over on peertube are also good and I recently remembered to watch them as I go* Otherwise ... any thoughts or requests on what else can happen here for those going through "The Book"? * I'm thinking of having posts on sets of chapters once the two twitch streams have gotten up to them. * So right now, both have gotten through the borrow checker chapter (ch 4). * The idea would be to have a reading club happen here too ... to allow written discussion/questions here for those not able to make the streams (or who like/prefer written discussion), but also to provide a retrospective for those who've gone through the streams. * Personally, in these discussions I'd post my understanding of the topic, look back on the quizzes to see what tripped me up, or any other practical issues I ran into, and post anything else I may have found that helped me on the topic. Basically to see what I actually learned from that chapter. * Thoughts?? * Another thing I can think of is challenges and exercises. I tried one a while back, but I think it was too much/long, so smaller exercises would probably work better for getting us thinking/coding in rust. AoC has come up and there are plenty of others. Would regular posts from such a thing be welcome or helpful??

15
10

Ownership is finally over! Ok, I *know* we're going to be seeing more of it throughout the rest of the book, but at least it should always be in the context of "doing" something else/useful. For example, grouping bits of related data into structs. # What? I will be holding the ninth of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). This week we begin chapter 5 "Using Structs to Structure Related Data"! Previous session details and recording can be found in the following lemmy post: https://jlai.lu/post/6557213 # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+2 (aka 6pm Central European Time) on Monday (2023-05-13). If you were present for a previous session, then basically the same time-of-day and day-of-week as that one was. **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). **Edit: here's the link to the recording https://youtu.be/h4l5Ksd5w7E** I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the chapter, both reading aloud the literal chapter text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

16
2

# What? I will be holding the eighth of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). This week we finish chapter 4: "Understanding Ownership" by reading through the "Ownership Recap (4.5). Previous session details and recording can be found in the following lemmy post: [https://jlai.lu/post/6353244](https://jlai.lu/post/6353244) # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+2 (aka 6pm Central European Time) on Monday (2023-05-06). That's around 4 hours after this post is created. If you were present for a previous session, then basically the same time-of-day and day-of-week as that one was. **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). **EDIT: here's the recording: https://youtu.be/3w7m5GM7eV8** I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the chapter, both reading aloud the literal chapter text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

10
0
https://rust-unofficial.github.io/too-many-lists/

This might be a more interesting dive into Rust for those with a fair amount of existing c and/or c++. I tried it out myself a few years ago. I had **fun** reliving the nightmare of implementing doubly-linked lists in C back in school! I never made it to the end of the book, though; it got wayyyy more complex around halfway than I could process at the time.

22
3

Hi all! So much happening in my personal life these past 2 weeks that I couldn't put aside the time or energy to host these sessions. Things are calming down a bit (plus I've missed doing the sessions), and so I'm happy to announce the date for the next session. # What? I will be holding the seventh of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). This week we will be continuing chapter 4: "Understanding Ownership". Last session we finished "Fixing Ownership Errors" (4.3). We will thus start from the beginning of "The Slice Type" (4.4). Previous session details and recording can be found in the following lemmy post: [https://jlai.lu/post/5991675](https://jlai.lu/post/5991675) # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+2 (aka 6pm Central European Time) on Monday (2023-04-29). If you were present for a previous session, then basically the same time-of-day and day-of-week as that one was. **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). **Edit: here's the recording: [https://youtu.be/OeyWDSJ-Y5E](https://youtu.be/OeyWDSJ-Y5E)** I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the chapter, both reading aloud the literal chapter text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

12
1

Just place to keep links to comments from this community that go "above and beyond" in helping someone out and really explaining or teaching. There'll be a link in the side bar. Feel free to add any links you like with a comment

14
4

### Intro I'm not on top of traits or generics but found myself looking some of them up anyhow, and came across the `Sum` trait. Here is the [Std Lib documentation on `Sum`](https://doc.rust-lang.org/core/iter/trait.Sum.html) (I believe). And I guess all of the generics and/or type logic and how they interoperate has thrown me for a bit of a spin ... so I thought I'd put my thoughts here. Maybe I'll work things out in writing it or maybe someone here can help me/us out? *A bit long ... sorry* --- ### Trait Definition From the docs and source, here is the trait's signature: ```rust // core::iter::Sum pub trait Sum<A = Self>: Sized { // Required method fn sum<I: Iterator<Item = A>>(iter: I) -> Self; } ``` ### First thoughts: Defined on elements not iterators? * The part that confused me at first was what `Self` is actually. Naively, I imagined it was referring to the iterator (or type that'd implemented `Iterator`) ... but that clearly can't be true because the return type is `Self`. * So ... `Sum` is implemented not on any collection but on the element type?! * If so, why not rely on the `Add` Trait at the element level, which is responsible for the addition operator (see [docs here](https://doc.rust-lang.org/std/ops/trait.Add.html#required-methods))? ### Kinda seems so? * So, in trying to understand this, I thought I'd look at the source of `Iterator::sum()` first figuring that it'd be the main implementation. * See [docs on sum() here](https://doc.rust-lang.org/core/iter/trait.Iterator.html#method.sum) and [source code here](https://doc.rust-lang.org/src/core/iter/traits/iterator.rs.html#3637-3643) * This is the `sum` you'd be calling in something like `vec![1, 2, 3].into_iter().sum()` to get `6`. ```rust core::iter::Iterator::sum fn sum<S>(self) -> S where Self: Sized, S: Sum<Self::Item>, { Sum::sum(self) } ``` * Ok, so the call of `Sum::sum(self)` clearly indicates that this is not where `Sum` is defined (instead it must be in `Sum::sum()` somehow). * Moreover, `self` is being passed into `Sum::sum()`, with`self` being the `Iterator` here ... which means there's no method being called on `Iterator` itself but something from another module. * Additionally, this method is bound by the generic `<S>` which is defined in the `where` clause as `Sum<Self::Item>` ... which ... *wait WTF is going on*? * So this method (`Iterator::sum()`) must return a type that has implemented the trait `Sum`?? * If that's correct, then that confirms my suspicion that `Sum` is implemented on the elements of an iterator (where I'm sure those comfortable with the generics syntax of the definition above are yelling *YES!! OF course!!*) * That's because the return type of `sum()` would generally have to be the same type as the summed elements, so `S` is both the type of the elements in the iterator and the return type of `sum`. All good. * And indeed, in the definition of the `type` alias `S` we've got `Sum<Self::Item>` which binds the return type of `Iterator::sum()` to the type of the iterator's elements (ie `Self::Item`) * `Self::Item` is technically the `Item` type of the `Iterator` which can, AFAIU, be defined as distinct from the type of the elements of the collection from which the iterator is derived but that's another story. ### Back to the beginning * So back to trying to understand the definition of `core::iter::Sum` (which I believe is the definition of the trait): ```rust // core::iter::Sum pub trait Sum<A = Self>: Sized { // Required method fn sum<I: Iterator<Item = A>>(iter: I) -> Self; } ``` * The trait itself is bound to `Sized`. I don't know the details around `Sized` (see [docs here](https://doc.rust-lang.org/std/marker/trait.Sized.html) and [The book, ch 19.4 here](https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait)) but it seems fundamental likely that it applies to vectors and the like. * The generic `A = Self` and its occurrences in the generics for the `sum()` function and its return type ... *are a lot*: * AFAIU, `Self`, ie the type on `Sum` is implemented for, must be the `Item` type for the `Iterator` that will be passed into the `sum` method. * But it must also be the return type of `sum()` ... which makes sense. * So the confusing part here then is the generic type of the `sum()` method: `<I: Iterator<Item = A>>`. * Remember, `A = Self`, so it's really `<I: Iterator<Item = Self>>` (right?) * This generic type is any `Iterator` whose `Item` (ie, the type that is returned each iteration) is the same type as `Self`. * Which means that if I want to sum a vector if `i32` numbers, I'd have to make sure I've implemented `Sum` not on `Vec` but on `i32` and defined it as a method that takes any iterator of `i32` (ie `Self`) elements to then return an `i32` element. * Ok .... ### Confirmation * We can look at the implementors of `core::iter::Sum` ( see [docs here](https://doc.rust-lang.org/core/iter/trait.Sum.html#implementors)) and check the source for the `i32` implementation ... * Which gives us [this source code](https://doc.rust-lang.org/src/core/iter/traits/accum.rs.html#149): ```rust integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } ``` * Which is using this macro [defined in the same file](https://doc.rust-lang.org/src/core/iter/traits/accum.rs.html#45): ```rust macro_rules! integer_sum_product { (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($( #[$attr] impl Sum for $a { fn sum<I: Iterator<Item=Self>>(iter: I) -> Self { iter.fold( $zero, #[rustc_inherit_overflow_checks] |a, b| a + b, ) } } ``` * which ... uses `fold()` (basically `reduce` but with an initial value) and plain addition in the anonymous/closure function `|a, b| a + b`. *What!?* ### Why? How? * Ok that was a long way to go to find the addition operator at the bottom of the heap of traits! * Hopefully I've grasped the mechanics?! * I'm not quite clear on why it's build this way. I'm guessing there's some flexibility baked into the way that the relevant implementation of `Sum` depends on the element type, which can be flexibly defined as the `Item` type of an `Iterator` independently of the type of the collection's elements. That is, an iterator can utilise a type different from the actual elements of a collection and then rely on its particular implementation of sum. And then this can be independent from `Add`. * But that feels like *a lot of obscure flexibility* for a pretty basic operation, no? * For example, this code doesn't compile because a type needs to be specified, presumably type inference gets lost amongst all the generics? ```rust // doesn't compile let x = vec![1i32, 2, 3].into_iter().sum(); // These do compile let x2 = vec![1i32, 2, 3].into_iter().sum::<i32>(); // turbofish!! let x3: i32 = vec![1i32, 2, 3].into_iter().sum(); ``` --- * Design choices aside ... * I'm still unclear as to how `Iterator::sum()` works ```rust fn sum<S>(self) -> S where Self: Sized, S: Sum<Self::Item>, { Sum::sum(self) } ``` * How does `Sum::sum(self)` work!? * `self` is the `Iterator` (so `vec![1i32, 2, 3].iter()`). * And `Sum::sum()` is the essential trait addressed above. * How does rust go from a call of a trait's method to using the actual implementation on the specific type? I guess I hadn't really thought about it, but it makes sense and it's what all those `Self`s are for. * In this case though, it's rather confusing that the relevant implementation isn't on the type of `self`, but because of the definition of `Sum`, the implementation is on the type of the elements (or `Item` specifically) of `self`. Sighs --- Thoughts??

9
8

A minor but interesting and illuminating point came up in a conversation that I thought was worth sharing, for those learning rust, in a separate post. I'm mostly just copy-and-pasting here. * See [comment here](https://lemmy.ml/comment/10363308) by [@Ephera@lemmy.ml](https://lemmy.ml/u/Ephera) --- TL;DR: The patterns you use in `match` statements and related syntax are (basically) available to you in `let` statements. **This is how destructuring works**!! *And what they're for with `let`*. But the patterns have to be "*irrefutable*" --- IE, they have to always be able to match the expression/value. --- For those who aren't aware, [here's the first section in The Book on patterns in `let` statements](https://rust-book.cs.brown.edu/ch18-01-all-the-places-for-patterns.html#let-statements). I think, if this is confusing, there are two points of clarification: 1. **All `let` statements involve patterns** (as Ephera states). They're all `let PATTERN = EXPRESSION`. * For ordinary variable binding, we're just providing a basic pattern that is essentially like a wildcard in that *it will match the totality of any expression and so be bound to the full/final value of that expression*. * It's only when the pattern becomes more complex that the pattern matching part becomes evident, as elements of the value/expression are destructured into those of the pattern. * EG, `let (x, y, _) = (1, 2, 3);` or Ephera's example below `let Something(different_thing) = something;` which extracts the single field of the `struct` `something` into the variable `different_thing` (handy!). 2. **`let` statements must use `irrefutable` patterns.** That is, patterns that cannot fail to match the expression. * For example, against a tuple, `(x, y, _)` will always match. Another way of putting it: `irrefutable` patterns are about destructuring not testing or conditional logic. * `if let` statements on the other hand can take both `irrefutable` patterns and `refutable`, but are really intended to be used with `refutable` patterns as they're intended for conditional logic where the pattern must be able to fail to match the expression/value. * See [The Book chapter on `refutability`](https://rust-book.cs.brown.edu/ch18-02-refutability.html) --- The nice and useful example provided by [@Ephera@lemmy.ml](https://lemmy.ml/u/Ephera) (in the original comment): ```rust struct Something(DifferentThing); let something = Something(DifferentThing::new()); let Something(different_thing) = something; ``` * Here, the variable `something` is a `struct` of type `Something` which contains one field of type `DifferentThing`. * In the final line, we're extracting that `DifferentThing` field with a pattern in a `let` statement. * IE, `Something(different_thing)` is the pattern. And it is *irrefutable* against all variables of type `Something`, as they have only one field.

25
2
https://rust-book.cs.brown.edu/ch06-03-if-let.html

I can't help but suspect it doesn't offer much and you may as well just use `match` statements for whenever you want pattern matching, however many times it might be slightly more verbose than what you could do with `if let`. I feel like I'd easily miss that pattern matching was happening with `if let` but will always know with `match` what's happening and have an impression of what's happening just from the structure of the code.

9
6

Hi all! # What? I will be holding the sixth of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). This week, we will be continuing chapter 4: "Understanding Ownership". Last week we finished "References and Borrowing" (4.2). We will thus start from the beginning of "Fixing Ownership Errors" (4.3). Previous session details and recording can be found in the following lemmy post: [https://jlai.lu/post/5871866](https://jlai.lu/post/5871866) # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+1 (aka 6pm Central European Time) on Monday (2023-04-15). If you were present for a previous session, then basically the same time as that one was. **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). **Edit: here's the recording: https://youtu.be/7XcluwdxBHQ** I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the chapter, both reading aloud the literal chapter text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

7
0

Hi all! I had to cancel last week's session at the last minute, so this week we'll just be covering what we would have covered, then. (recap of the session info for completeness' sake:) # What? I will be holding the fifth of the secondary slot/sessions for the Reading Club, also on "The Book" ("The Rust Programming Language"). We are using [the Brown University online edition](https://rust-book.cs.brown.edu/title-page.html) (that has some added quizzes & interactive elements). This week, we will be continuing chapter 4: "Understanding Ownership". Previous session details and recording can be found in the following lemmy post: https://jlai.lu/post/5452538 # Why? This slot is primarily to offer an alternative to the main reading club's streams that caters to a different set of time zone preferences and/or availability. (also, obviously, to follow up on the previous session) # When ? Currently, I intend to start at 18:00 UTC+1 (aka 6pm Central European Time) on Monday (2023-04-08). If you were present for a previous session, then basically the same time as that one was. **Please comment if you are interested in joining because you can't make the main sessions *but* would prefer a different start time (and include a time that works best for you in your comment!)**. Caveat: I live in central/western Europe; I can't myself cater to absolutely any preference. # How ? The basic format is: I will be sharing my computer screen and voice through an internet live stream (hosted at https://www.twitch.tv/jayjader for now). The stream will simultaneously be recorded locally and uploaded afterwards to youtube (also, for now). **Edit: the recording is now uploaded on youtube**: https://youtu.be/zueZGhlkiyE I will have on-screen: - the BU online version of The Book - a terminal session with the necessary tooling installed (notably `rustup` and through it `cargo` & "friends") - some form of visual aid (currently a digital whiteboard using www.excalidraw.com) - the live stream's chat I will steadily progress through the chapter, both reading aloud the literal chapter text and commenting occasionally on it. I will also perform any code writing and/or terminal commands as the text instructs us to. People who either tune in to the live stream or watch/listen to the recording are encouraged to follow along with their own copy of the book. I try to address any comments from live viewers in the twitch chat as soon as I am aware of them. If someone is having trouble understanding something, I will stop and try to help them get past it. # Who ? You! (if you're interested). And, of course, me.

18
1