Тёмный

Crust of Rust: Smart Pointers and Interior Mutability 

Jon Gjengset
Подписаться 87 тыс.
Просмотров 126 тыс.
50% 1

Опубликовано:

 

30 сен 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 207   
@derekdreery
@derekdreery 4 года назад
These are really great, and they fill the "intermediate" gap in rust tutorials, which is very valuable!
@jonhoo
@jonhoo 4 года назад
Thanks, I'm glad you think so!
@dmitrij34
@dmitrij34 4 года назад
@@jonhoo , really enjoy the content. A little question, if you don't mind... I've just recently started to check out Rust, so sorry if it's a dumb question - your implementation of the Cell, wouldn't it leak memory on .Set(...)? Who is responsible for the cleanup? I doubt unsafe cell would do that. Are we effectively throwing away the raw pointer?
@jonhoo
@jonhoo 4 года назад
Ah, no, not quite. `set` overwrites the old value through a `&mut T` (that's what the dereference of the raw pointer we get back from `UnsafeCell` produces). When you change a value through a `&mut T`, Rust automatically drops the old value for you :)
@dmitrij34
@dmitrij34 4 года назад
@@jonhoo Interesting... From what I've heard in a lot of the Rust tutorials I've assumed so too. And then I've took a look at the Cell implementation of the Cell in the standard library: pub fn set(&self, val: T) { let old = self.replace(val); drop(old); } For some reason drop here is explicitly called. As I understand, the replace returns T, and it should be automatically destroyed when the scope ends, but why drop then? Took the code from here: doc.rust-lang.org/src/core/cell.rs.html#344
@jonhoo
@jonhoo 4 года назад
That's actually for a slightly different reason - the standard library Cell has a replace method, and rather than copying the unsafe code from replace into set, they re-use replace in set. In which case they also need to deal with the return value. They don't need the explicit drop there though, that's probably just for exposition.
@nikis05
@nikis05 4 года назад
My favourite part is: “why is this working?? Great, it failed!” :D Jokes aside, thanks for an amazing tutorial!
@ChristopherBreeden85
@ChristopherBreeden85 4 года назад
I enjoy how Jon keeps trying to write incorrect code to show why it's incorrect but is continually stopped by the compiler :)
@troglodytto
@troglodytto Год назад
Rust compiler is beautiful in that sense. Literally forces you to write correct code.
@Tamazakis
@Tamazakis 3 года назад
std::borrow::Cow. milk it. shake it. drink it... now you own it... no need to return it. the magic of Cow
@ChronosWS
@ChronosWS 4 года назад
~30:00 I very much appreciate that writing a failing test to show concurrent access leads to inconsistent results is hard - which is exactly what makes concurrent programming in general hard, and why Rust is so nice for making concurrent code that works.
@Knirin
@Knirin 2 года назад
The test worked but not in the way he expected it to. The allocation was occurring separately from the mutation of the UnsafeCell’s internal value. Which array pointer made it into the UnsafeCell last changed between test runs.
@GenusvProgramming
@GenusvProgramming 4 года назад
Thank you for this! it was really helpful. I love this Crust of Rust series, I for sure will have to watch it a couple of times.
@beastle9end499
@beastle9end499 3 года назад
I recently switched from C++ to Rust and that type of content is exactly what I was looking for. Thanks very much:)
@rubenstukken6940
@rubenstukken6940 2 месяца назад
I started looking into switching. But this kind of terrifies me. I should probably wait till I encounter a scenario where I what to do something legit and know how to do in C++ and then look into these types.
@bkaankose
@bkaankose 3 года назад
This is one of my best videos of your collection here. Thank you for doing advanced stuff. Even though Cell might seem like a structure that don't have a lot of use cases, it helped me to understand a lot of intermediate concurrency and threading problems in programming.
@VivekYadav-ds8oz
@VivekYadav-ds8oz 3 года назад
Those two questions about taking a &mut and storing it, and modifying directly through the NonNull ptr rather than using a Cell, are what I had in my mind too! That's why you should ask questions if you're live, you don't know who else might be thinking about that too.
@chsblue2
@chsblue2 3 года назад
A cow literally started mooing outside when you began to explain Copy On Write. Thank you for sharing your knowledge. Very helpful!
@cat47
@cat47 8 дней назад
that's pretty ironic
@sedat4842
@sedat4842 3 года назад
I have been looking for some intermediate/advanced tutorials on Rust, but wasn't lucky so far. Unfortunately, most talks in conferences are introductory but hese videos are great for me to continue learning. Thanks a lot Jon! Also, I donate monthly to GiveDirectly and I recommend everyone to do so.
@sortof3337
@sortof3337 Год назад
1:41:13 example aldo doesn't compile anymore but this compiles ``` fn main() { let foo; let mut t; t = String::from("Hello"); foo = Rc::new(Foo { v: &mut t }); } ```
@tsalVlog
@tsalVlog 4 года назад
the deref explanation made a WHOLE bunch things just click for me.
@RitobanRoyChowdhury
@RitobanRoyChowdhury 4 года назад
You explained Mutex as an RwLock which doesn't distinguish between readers or writers. When might be a practical situation where a Mutex is a better choice than RwLock?
@realsong-fake
@realsong-fake 4 года назад
From my experience RwLock only makes sense when I have way more read than write on the shared state. Otherwise I find Mutex to be more useful especially under contention. That being said it's best you measure it yourself for your use case.
@rufflefpv
@rufflefpv 4 года назад
#34:30 the best way to reproduce these kinda bugs is to use a barrier before the actual operation that's supposed to fail
@christopher8641
@christopher8641 Год назад
This video has been a godsend for understanding some of these concepts. You are a valuable teacher! Thanks for these vids, they have really pushed my understanding forward by quite a bit
@Codeaholic1
@Codeaholic1 2 года назад
One of the better simple explanations of PhantomData and the drop check.
@nilshaberstroh2705
@nilshaberstroh2705 3 года назад
Delicious content. The way you explained these pointer types makes it actually possible to distinguish and remember them. Very very valuable video.
@aqua3418
@aqua3418 2 года назад
Regarding turning things into *const and *mut. It is UB to turn a & reference into an &mut. So *const generally signifies it's an immutable reference, and *mut generally signifies it's a &mut, and it should always be kept the way. Of course, if it comes to memory passed from FFI, all bets are off and you'll need to know how the FFI is managing the memory and use proper Rust C structs that properly imitate the c ones, and blah blah blah. Advanced topic for another time. The main point is the Rust ones are easy to remember.
@Trequetrum8
@Trequetrum8 Год назад
I'm not sure why `x1.set([1; 1024])` should've failed. Are we assuming that this is being written usize bits at a time into memory and therefore the threads might clobber each other? Certainly I wouldn't expect my compiled code to have a loop here setting the indexes of my array. The compiler should already have inlined the binary representation inside the binary executable.
@BboyKeny
@BboyKeny Год назад
I was thinking that the threads we're in sync perfectly like thread 1 sets 1 at the first element then thread 2 sets 2 at that place. Then sometimes the first thread starts 1 tick later. That's why it was mostly all 2's and sometimes all 1's. But I might be completely wrong about this.
@Trequetrum8
@Trequetrum8 Год назад
@@BboyKeny Maybe we should just compile this and look at what's happening. I would be very surprised to see either thread setting anything via indices.
@manjunath3929
@manjunath3929 4 года назад
I had spent hours to understand smart pointers but this video helped me to understand in greater depth than I could reading docs. You are really gift to rust community and people like me who are new to rust. Thanks a lot Jon
@oskarberndal5310
@oskarberndal5310 4 года назад
Hello Jon! Thanks for the great video =) I love coding along with these. It never really became clear to me why I would prefer an 'Rc' instead of a normal shared reference '&'. It seems to me (and this is probably wrong) that the benifits of '&T' and 'Rc' are similar except that the compiler sometimes can infer when all the references through '&T' are dropped and we get the 'T' back. However, we can never really depend on all the references through 'Rc' being dropped at any point in our code, so we could as well just use a '&T' which never gets dropped (if that makes sense). I would be very happy if you could elaborate why I'm wrong here but you are a busy man and I understand if you have other things to do - anyway thanks for the awesomely prepared videos cheers from sweden =)
@jonhoo
@jonhoo 4 года назад
Hi Oskar! Glad you're enjoying the videos :) So, the big difference between &T and Rc is that the former borrows a value, whereas the latter has "partial ownership" of a value. With a &T, the compiler knows, at compile time, what value the reference borrows, and how long that value is live for. And it checks that the &T never outlives the value (for example because the function holding it returns), and that it never conflicts with another type of borrow (&mut T). With Rc, there is no value "being borrowed", not really. There is an owned value that lives on the heap (think Box), where the Rcs organize among themselves so that only when the last Rc goes away is the Box dropped. By upholding that contract, every Rc can reference the T safely, since they all do so with shared references, and the target is always valid (since it's owned and on the heap).
@luckystrike91
@luckystrike91 14 часов назад
34:56 you probably need to use a std::sync::Barrier and arm processor for such purpose
@catalinneagu1417
@catalinneagu1417 2 года назад
You're a really good teacher. Thank you. Also donated
@EgnachHelton
@EgnachHelton 4 года назад
An interesting way to think about RefCell vs Mutex: In multithreaded code, Mutex force a thread to wait for another thread leaving the critical section. RefCell does the same in single threaded code except that it knows that "the other thread" would never leave the critical section since there's only one thread, so it just terminates the program
@rsalmei
@rsalmei 20 дней назад
@jonhoo At 26:30, it triggered UB! Miri reports an error. It seemed to work because the reference was overwritten (UnsafeCell is repr(transparent)).
4 года назад
Looking forward to the the continuation on mutex and rwlock, great stuff
@ilyasb4792
@ilyasb4792 3 года назад
"Great, it failed, fantastic" 36:29 It wasn't even ironic lmao
@jonhoo
@jonhoo 3 года назад
Being able to predict exactly how something won't work is a special kind of good feeling!
@karthiknedunchezhiyan1171
@karthiknedunchezhiyan1171 4 года назад
Really enjoyed the video, keep going!
@ev3rybodygets177
@ev3rybodygets177 8 дней назад
Saying cells are nice for flag state knowing refcell was going to use it in that fashion was a nice touch! Clever!
@pauloalmeida2126
@pauloalmeida2126 2 года назад
Came here for PhatomData's explanation; First thing Jon said: "This is going to make your head hurt";....... Missing accomplished bro :)
@luctielen
@luctielen 3 года назад
Thanks, this video in the series especially explained a lot of things that were previously unclear to me before. Kudos!
@VivekYadav-ds8oz
@VivekYadav-ds8oz 3 года назад
I thought if I was writing *fn foo(bar: T) {}* , I was either taking ownership of a non-reference type, or taking a static reference! After all, I thought, that's why you can define it like this: *fn foo(bar: &T) {}* , because you needed to distinguish b/w the two! So now wherever I assumed that I am the owner of type T and used _unsafe_ assuming this invariant, I now need to be careful that I might just have been passed a reference :(
@jonhoo
@jonhoo 3 года назад
Ah, yes, is _very_ much not guaranteed to be owned. T + 'static is guaranteed to be usable for as long as you hold on to it, so that's perhaps what you're after. Think of it as " means _any_ type T", and &T is more constrained, as it only allows _references_ to any type.
@karelhrkal8753
@karelhrkal8753 2 года назад
Hey, I added a comment the other day with a link to the Rust playground and I don't see it anymore. Is RU-vid automatically deleting comments with links or something?
@VivekYadav-ds8oz
@VivekYadav-ds8oz 3 года назад
28:30 I allocated 1000 50-character long Strings to force the deallocation of the referenced String, the program still doesn't crash/panic. I think that's because you don't really have a reference/pointer to the String so much as you have a pointer/reference to the _value_ member variable of the _UnsafeCell_ struct, which still remains a valid String. If the Allocator was the reason, it wouldn't have printed "world" in that example it would've still printed "hello".
@jonhoo
@jonhoo 3 года назад
It's more likely because deallocation doesn't immediately return the memory to the operating system (which would cause a segfault on access), or wipe that memory in the meantime (which would yield garbage results). Usually, deallocation just means "make available to other allocations", so if you just allocate lots of other strings with the same contents, you'd just expect to have the same memory being overwritten many times with the same value, which means you wouldn't notice when trying to read through an old pointer.
@joeldsouzax
@joeldsouzax 7 месяцев назад
I think the reason the Cell Test didnt show up that interleaving because you either set the entire cell value as an array of 1 or 2 ...10240 elements, this meant that that OS must have done both concurrently and the one that was did it last was shown in the print.
@WindBringsMemories
@WindBringsMemories 3 года назад
Great tutorial! Liked the debugging part as well :)
@billjohnson6863
@billjohnson6863 3 года назад
Super useful! Thanks for doing these.
@secondengineer9814
@secondengineer9814 Год назад
So the only difference between Cell and UnsafeCell seems to be the function signatures?
@RM-ep2dc
@RM-ep2dc Год назад
29:00 just put your String::from or new into a block, so it gets dropped.
@manojbabu3640
@manojbabu3640 2 года назад
To check if you have all 2's or 1's set, may be you could print sum.
@juchemz
@juchemz 11 месяцев назад
Is there any reason why Cell doesn't use Clone instead of Copy for the bound on get?
@yakupc
@yakupc 4 года назад
I respect what you do. These are great videos. You should consider enabling the support button on RU-vid
@jonhoo
@jonhoo 4 года назад
Unfortunately I can't for visa reasons :) But maybe one day!
@bowarc
@bowarc 11 месяцев назад
unsafe is more like a 'source: trust me bro' tag than something not safe to use
@MauriceChavez353
@MauriceChavez353 3 года назад
Make Jon the rust mascot!
@xieen7976
@xieen7976 2 года назад
first still exsited, because it not reference.. it is a copied value
@willemvanderveen7567
@willemvanderveen7567 3 года назад
Keep it up man great videos!
@VivekYadav-ds8oz
@VivekYadav-ds8oz 3 года назад
Also why being Send is opt-out? That seems very dangerous that it isn't opt-in. What if I'm just implementing Structs as I do everyday, and one of them isn't really safe to send to threads, and I forget to opt-out of it. Then send it over? Kinda curious why that's the case.
@jonhoo
@jonhoo 3 года назад
Send is an auto-trait, so it's not _quite_ that it's opt-out. A type is !Send if _any_ of its members are !Send. And raw pointers for example are !Send. So I think it's very unlikely for you to have a type that truly isn't thread safe that is still Send unless you use unsafe. And if you use unsafe, thread-safety is one of the (many) things you have to check. Even then though, the auto-implementation will probably make your type !Send already, just because it almost certainly includes some kind of raw pointer.
@VivekYadav-ds8oz
@VivekYadav-ds8oz 3 года назад
@@jonhoo That's good to know that in practicality my types would be !Send unless I make them Send by unsafe impl. But I'm still confused why it was decided that Send would be an auto-trait? I have to wrap all my types in Arc anyways before sending (it I want shared ownership). So it's not like trivial structs benefit from this auto-trait, as I have to wrap my type with a Send type anyways. My guess is that you can't even send a clone of your type if you wanted because you have to move the clone too. That _would_ get annoying.
@jonhoo
@jonhoo 3 года назад
I'm not sure I follow? Being able to send a type to another thread is very common, such as passing it to a closure in thread::spawn or sending it over a channel. Those cases don't require sharing, just sending, and it'd be really unfortunate if you had to wrap all of those in Arc unnecessarily.
@mithradates
@mithradates 3 года назад
Interesting, the code at 1:34:38 doesn't generate an error anymore!
@sproccoli
@sproccoli 7 месяцев назад
this is the perfect way to teach/learn this stuff.
@VivekYadav-ds8oz
@VivekYadav-ds8oz 3 года назад
I still don't get why you would use a _Cell_ type for storing the refcount. We're in a single-threaded environment (as far as Rc is concerned), so there should be no race conditions, we can just modify refcount through the pointer!
@jonhoo
@jonhoo 3 года назад
Even if a type is !Send, it's not okay to give out a mutable (i.e., exclusive) reference to a value contained inside that type. Consider a single-threaded program that walks a cyclic data structure, and ends up vising a single node twice. It then ends up with two concurrent mutable references to a single value. Now imagine it passes those to a method like mem::swap - bad things will likely happen. Worse yet, the compiler is allowed to optimize based on mutable references being exclusive, so it might apply an optimization that assumes that the second reference will not change (since we have an exclusive reference), but that optimization is invalid since the same value can change by changing through the first reference. It is undefined behavior to _ever_ have multiple mutable references to a single value concurrently, no matter whether you're in single-threaded or multi-threaded context. Hence the use of Cell, which allows mutation through a shared reference (though note it never _gives out_ a mutable reference).
@VivekYadav-ds8oz
@VivekYadav-ds8oz 3 года назад
@@jonhoo Damn, is it really undefined behaviour to do unsafe { *refcount += 1 } ? That's wild if that's true. It seems like a very simple case where we don't pass a reference (mutable or shared) to anyone. We modify it, but only through our code. Using a _Cell_ here would be more out of principle than it being actually needed, imo.
@jonhoo
@jonhoo 3 года назад
@@VivekYadav-ds8oz Mutating directly through a shared reference without UnsafeCell is *always* undefined behavior, precisely because the compiler may optimized based on the assumption that the pointer isn't shared, which would be invalid (and this produce incorrect code) if it was shared. You could do it with UnsafeCell if you *knew* it was truly not shared (even on the same thread), because that prevents some of those optimizations.
@Agryphos
@Agryphos 2 года назад
I was able to get the interleaving that Jon attempted around 34:00 by using [u8; 320000] as inner values for the Cell. Most of the time the result was uniform but I got interleaving every now and then
@Knirin
@Knirin 2 года назад
That is a separate bug. Probably one in the compiler not Your or Jon’s code. Interleaving of the values is not the expected behavior. The expected behavior is what Jon got. An array that is unpredictably either all 1s or all 2s. The data race should be in the final assignment not in the array creation. If interleaving was the expected behavior data corruption from any two threads using the stack in a similar time window would cause a lot of havoc.
@Agryphos
@Agryphos 2 года назад
@@Knirin That's what I thought at first as well, that both would be creating a full array and the race is who gets to set the pointer. Interesting to know that is correct and that I had a separate bug here.
@Knirin
@Knirin 2 года назад
@@Agryphos Having had more time to think about it, I think the issue is in the memory allocator. It may not be thread safe for stack allocations in excess of the CPU’s L1 cache. Which are generally under 64KB. You may need to get a few times over the L1 cache size to reliably see an issue. I am kind of surprised that Rust tries sticking multi KB data structures on the stack. Every other compiled language I have dealt with is throwing things onto the heap before a data structure is a KB in size, usually transparently to the user. Transparently until your compilation target doesn’t have an operating system or you are trying to write a kernel in said language anyway. The jokes about C being an easier to read assembler aren’t far off.
@alexanderadhyatma3126
@alexanderadhyatma3126 4 года назад
Thank you Jon, your tutorial are very valuable for me. Also, Plug can be used to run tests from your neovim (no need for another tmux split / tab)
@jonhoo
@jonhoo 4 года назад
Ah, but I prefer to run the tests in a separate and dedicated shell :)
@user-ov5nd1fb7s
@user-ov5nd1fb7s 4 года назад
Great videos. Keep em coming.
@emnul8583
@emnul8583 20 дней назад
I didn't realize just how informative the standard lib documentation was. You've inspired me to study the documentation for the entire Rust standard library. See y'all in about 4 months 🫡
@logicprojects
@logicprojects 4 года назад
Great work, Thanks for all you do
@karelhrkal8753
@karelhrkal8753 Год назад
1:27:49 I keep wondering: why do you need to manually drop the "inner" value? Will the constructed Box not destroy it?
@karelhrkal8753
@karelhrkal8753 Год назад
1:21:39 Oh, "inner" is a raw pointer and dropping it doesn't (really) do anything. The actual data of T is still dropped only once by the Box. Thanks.
@dickheadhex418
@dickheadhex418 3 года назад
I think the array example for threading racing didn't work because the array values aren't written individually to the unsafe cell, instead each time set() is called the underlying unsafecell is assigned a new array so it will either be all 2s or all 1s but never interleaved. But also because of how fast the computer is, the order is maintained usually so it shows 2s everytime. is this the right way to look at it?
@kevincarvalhodejesus4473
@kevincarvalhodejesus4473 5 месяцев назад
That's the best rust channel on youtube. I really love such deep and explanatory videos. I been watching these series and now i feel like rust is starting to click on my mind. Thank you so much Jon for such a great content!
@menfie
@menfie 4 года назад
You do `escape + Shift-O` after opening bracket to get into it. I was doing same before I discovered `let delimitMate_expand_cr=1` option for delimitMate. Highly recommended.
@filipbielejec9038
@filipbielejec9038 3 года назад
From ~55:00 - is there a reason you cannot implement Drop (and DropMut) for RefCell directly and going via these helper Ref/RefMut types?
@FreemanPascal
@FreemanPascal 2 года назад
Jon, is your vim configuration available? I would like to setup vim to work with Rust and yours appears to work really well for that.
@viewing4748
@viewing4748 2 года назад
Does rwlock guarantee any sort of fairness between readers and writers or is that something you'll have to implement yourself? Can starvation happen with rwlock? In general should I be using rwlock for threaded apps or using crates liek tokio and rayon? are there other popular crates do that kind of stuff with?
@TheHellst0rm
@TheHellst0rm 2 года назад
Thanks for this series! I wonder if you could make a stream for advanced Cargo/build topics? E.g. linking to native libraries, passing compiler parameters, writing Bild scripts, different targets etc. Maybe even something about linkers in general and how Rust interfaces with it (it's often discussed in C courses, but somehow a bit neglected in Rust).
@monawoka97
@monawoka97 5 месяцев назад
These are seriously university quality lectures. I cannot tell you how much I appreciate you making all these!
@daltontinoco7084
@daltontinoco7084 2 года назад
I love how you try and show errors in rust, but rust is like, "Nah dude, I can make it work, trust me!" Unsafe code is hard to write lolol. Good video, earned my sub for sure. Thankyou!
@uoweme5grand
@uoweme5grand 2 года назад
These videos are great. Just wondering for the rest of the people watching (those of you who are coming across these concepts for the first time or maybe had only heard about it), does it also take you guys 3 to 4 times the video length to fully understand everything? It takes me a while ...
@artyomostrikov
@artyomostrikov Год назад
Thanks for a nice video that gives important knowledge on a really vital topics with examples! I hadn't known some things exist in Rust until watching these videos.
@chaudharypraveen98
@chaudharypraveen98 2 года назад
Awesome. Your way of explanation is magnificent. Thanks for the making tutorial.
@sortof3337
@sortof3337 Год назад
The bad example with bad array consistently fails on my older machine but doesn't fail on new one. These tutorials are so vaulable and insightful. I have literally learned so much from your videos. tysm.
@karelhrkal8753
@karelhrkal8753 2 года назад
19:50 You don't even need threads to break it. Just make a reference *into* the value stored in the cell, and then replace the value. Boom, instant dangling pointer.
@eddieh7962
@eddieh7962 2 года назад
This is so helpful! I knew there were tons of places in rust code where I got yelled at because of having two mutable references, even if those references never existed at the same time in a single threaded app. I guess I can use Cell for situations like this!
@bongjunjang5683
@bongjunjang5683 4 года назад
pure gold
@Kodlak15
@Kodlak15 Год назад
Thank you for the time you have put into this series. It’s been remarkably helpful! My brain is overheating a bit after this one 😅
@sputnick1
@sputnick1 10 месяцев назад
This has got to be the most comprehensive explanation of rust’s smart pointer types ❤
@debasishraychawdhuri
@debasishraychawdhuri 4 года назад
I honestly don't understand why this video has so few likes. This is what I have been looking for from the moment I started learning rust.
@EgnachHelton
@EgnachHelton 4 года назад
6:24 No, Cell has the same memory layout as T thus cannot be use as recursive type storage.
@mavichovizana5460
@mavichovizana5460 3 года назад
ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-8O0Nt9qY_vo.html after I put this `drop(inner)` and use inner afterward, the code can still compile. I'm confused since you mentioned that after the drop, `inner` can't be used.
@jonhoo
@jonhoo 3 года назад
Ah, yes, I was being overly eager there. I explain what's going on over in gist.github.com/jonhoo/7cfdfe581e5108b79c2a4e9fbde38de8#gistcomment-3805900
@mavichovizana5460
@mavichovizana5460 3 года назад
@@jonhoo Thanks a lot! Love your crust rust series! Fantastic vlogs!
@veetaha
@veetaha 4 года назад
@Jon Gjengset, might I ask you to increase the mic volume? It is too low to be able to listen to w/o headphones on both of my laptops...
@jonhoo
@jonhoo 4 года назад
Hmm, that doesn't sound right. Is the volume in the RU-vid player set too low perhaps? The audio recording level is pretty standard for videos as far as I can tell?
@RandomUser311
@RandomUser311 4 года назад
@@jonhoo it's somewhat low but not terribly bad on my tablet as well.
@jonhoo
@jonhoo 4 года назад
Interesting. My recording level is where all the sources I've found on the topic say they should be, so not sure what's happening then.. I'll see if there's anything I can do about it for next video!
@veetaha
@veetaha 4 года назад
@@jonhoo Well even having the volume slightly higher won't hurt because lowering it is way easier than reaching the ceiling of the max volume and not being able to increase it to the satisfying level. I should say that listening with headphones is alright, but maybe it's just my fridge is overly loud in the background ;D
@jonhoo
@jonhoo 4 года назад
I actually just now found the problem! It looks like RU-vid only performs loudness _reduction_, not boosting, so it requires that you perform loudness normalization before uploading if your input signal is relatively quiet (which my voice is). I sadly can't fix the _current_ video, but will make sure that future videos have an appropriate audio level!
@jonas-mm7em
@jonas-mm7em 2 года назад
Thanks Jon for the great video content once again. It's really interesting and gives concrete examples of harder to grasp Rust notions.
@SomeNullBytes
@SomeNullBytes 2 года назад
At 28:16, is it possible that it was due to short string optimization?
@hscowef4662
@hscowef4662 4 года назад
Very nice video, I was struggling to understand unsafe but watching this after I saw someone share it in the Rust Community Discord server helped me a lot thank you :)
@leolin652
@leolin652 11 месяцев назад
Thank you!!
@cryptomando
@cryptomando 2 года назад
Thank you Jon
@rurunosep
@rurunosep Год назад
I think that the PhantomData in the Rc might not be necessary. I noticed in the PhantomData chapter of the Nomicon there's a section that says that if you implement Drop on a Vec, for example, the compiler will automatically consider that Vec owns values of type T (at least for the purposes of the drop check?) even though it actually just owns a pointer. And I imagine it works exactly the same in the case of our Rc here.
@jonhoo
@jonhoo Год назад
There's currently a lot of debate around PhantomData and the drop check, so the discussion around there may be slightly dated. I recommend github.com/rust-lang/rust/pull/103413 for the latest discussion.
@NicholasShankland
@NicholasShankland Год назад
Trying to learning rust, coming from a javascript career, and trying to transition into things i find more interesting than daily redux meandering. Very helpful. I don't have a cs degree, so in trying to learn rust i am also trying to learn cs. So the deeper explanations are wildly more helpful than just pure 'x does y', without the 'because' I will never actually be able to write anything useful... so thanks!
@abdullahajibade7210
@abdullahajibade7210 10 месяцев назад
if you want to learn or you learning. there are videos for that. ppl could recommend some for you if you want. there are alsoo full tutorial as the video is centerred on smart pointer
@paulmoore7964
@paulmoore7964 4 года назад
excellent - v helpful. Do you take input for future talks? I am 100% confused by this issue stackoverflow.com/questions/63240439/trying-to-do-a-thread-join-in-a-method doing a join inline as opposed to putting it in a function. THis one I cannot get my head around. I know how to make it work using Option, but dont get why. And drill into the difference between Copy and Clone, And the difference between foo and &*foo - which for a C dev is v confusing
@jonhoo
@jonhoo 4 года назад
I highly recommend you read the Rust book, which covers most of those topics :)
@nammari4276
@nammari4276 Год назад
Incredible value. I love these!
@huxleyrummy9544
@huxleyrummy9544 4 года назад
Just started watching the video. As Jon says, "it seems antithetical". From knowing some Rust, it sure seems. If so, is these Cell and RefCell types made with some special compiler support or are they just regular vanilla rust with maybe some unsafes?? Haven't watched the rest of video though neither searched theses types source code :D
@jonhoo
@jonhoo 4 года назад
Hopefully the rest of the video explained it sufficiently!
@michaelritsema7108
@michaelritsema7108 4 года назад
Are you sure what you say at 29:00 is accurate? It seems like this was the exact thing Rust is trying to prevent from happening. I'm new to rust but it seems to be it works and will always work because you are still pointed to the same underlying UnsafeCell type. Perhaps because mem::replace uses the same memory address not matter what you replace it with. I'd be interested to hear your feedback on this.
@jonhoo
@jonhoo 4 года назад
Yes, absolutely, the statement there is accurate. And yes, Rust prevents those things from happening _when you're writing safe code_ . But here, we are specifically writing unsafe code, which gives us the ability to fiddle with raw pointers, and there it is up to _us_ to uphold the safety contract. What I'm trying to explain at that segment is why we need to not give out references from Cell - it's because doing so would mean that the user could write code that references invalid memory without anything in _their_ code being unsafe. I think maybe part of what has you confused is that String itself is also a pointer to some heap allocation. When we print a string, it's true that the location of the UnsafeCell hasn't changed (so the pointer to the String hasn't changed), but the pointed-to value by that String _has_ changed. This might be clearer if I'd dereferenced the pointer to get a &str directly to the string on the heap, rather than just go one level deep to get a &String. Hope that helps a little!
@1karaden
@1karaden 4 года назад
No big deal but there are uncomfortable noises in your microphone everytime your hands hit the your desk. Maybe you can try to isolate your mic from your desk's vibrations. :) I watch all your vids about Rust this is why i noticed it.
@jonhoo
@jonhoo 4 года назад
Oh, that's weird, I already have a shock mount that should take care of that. Can you point me at a time code when it happens?
@sodiumsalt
@sodiumsalt 3 года назад
Might I suggest delimitMate nvim extension? You seem to be manually expanding {} a lot, and it has automatic {} expansion on carriage return.
@jonhoo
@jonhoo 3 года назад
I despise anything that automatically inserts things into my editing buffer, because my experience is that they inevitably get in the way. I'd rather type the extra character :p Generally I'm not bottlenecked by typing but by my own brain!
@sharperguy
@sharperguy 4 года назад
I think I've seen you use these types in other videos. However, I don't recall you explaining in detail WHY you needed it in that case. I haven't seen many of your videos yet, though. Are there any where you are writing an example, and using these types, and explaining in detail why it's needed?
@jonhoo
@jonhoo 4 года назад
I think the standard library documentation gives pretty decent examples of when you might need each one, but the basic summary is: - You need Rc/Arc for when you want to share access to a value for an indeterminate amount of time. - You need Cell for when you want the ability to replace a shared value. - You need RefCell/Mutex for when you need to mutate a shared value.
@farseendeveloper461
@farseendeveloper461 4 года назад
How do you move firefox's navigation bar to the bottom? Didn't it get messed up when they changed the address bar recently?
@jonhoo
@jonhoo 4 года назад
I'm continuously updating my userChrome.css over at github.com/jonhoo/configs/blob/master/gui/.mozilla/firefox/chrome/userChrome.css :)
@FlaviusAspra
@FlaviusAspra 4 года назад
Question before we dive into Cell: why were the normal references with &, mut&, etc at the syntax level not enough? Or why was the syntax of the language not extended for this interior mutability things?
@jonhoo
@jonhoo 4 года назад
At the language level, you only have two types of references: shared (&) and exclusive (&mut). Rust lets you modify things through the latter, but not the former, because that is the only case where it's _definitely_ safe to do so. If no-one else has a reference, then there cannot be concurrent reads or writes to the value, and you cannot invalidate any other references by changing the thing pointed to. The same is not true for shared references, so Rust does not allow modification through those references. Interior mutability types (types that let you modify through a shared reference) let you do that because they maintain additional, special-case invariants that the compiler cannot check, that ensure that no conflicts arise even if you modify through a shared reference. There are _lots_ of ways to do so (CPU atomics, Mutexes, Cell, RefCell, etc.), and so it's not clear how the language would be "extended" to allow them. They all rely on implementation details of some particular algorithm.
@jacklong2182
@jacklong2182 2 года назад
Great tutorial , thanks for share
@maspe1
@maspe1 3 года назад
Why doesn't Cell have trait bounds on its T? What good is a Cell around a T that doesn't implement Copy?
@jonhoo
@jonhoo 3 года назад
In general Rust prefers to have bounds on impls, not structs. There are a couple of reasons for that, but the primary one is that it avoids reduces how many times the bounds have to be repeated throughout your code base, and the code base of anyone embedding your type.
@zahash1045
@zahash1045 2 года назад
Why he uses discord light theme tho
@tochiukegbu195
@tochiukegbu195 2 года назад
LOL I was looking for this comment
@alexzander__6334
@alexzander__6334 2 года назад
great videos. thanks.
@FlaviusAspra
@FlaviusAspra 4 года назад
Question about Cell: why would we use Cell at all? Why not simply pass T or & T to a method, but Cell?
@jonhoo
@jonhoo 4 года назад
You would rarely pass a Cell to a function. But you _would_ pass a &Cell to a function. Or, more commonly, something like an Rc. Those are the cases where Cell is useful - when you have multiple shared references to the Cell, and you want to mutate through _one_ of them.
Далее
Crust of Rust: Iterators
1:26:27
Просмотров 100 тыс.
Crust of Rust: Functions, Closures, and Their Traits
1:06:40
Teeth gadget every dentist should have 😬
00:20
Просмотров 975 тыс.
БЕЛКА ЗВОНИТ ДРУГУ#cat
00:20
Просмотров 788 тыс.
КОТЯТА В ОПАСНОСТИ?#cat
00:36
Просмотров 1,8 млн
Use Arc Instead of Vec
15:21
Просмотров 146 тыс.
but what is 'a lifetime?
12:20
Просмотров 73 тыс.
The Box Smart Pointer in Rust
12:18
Просмотров 72 тыс.
Crust of Rust: Send, Sync, and their implementors
1:07:04
Crust of Rust: Lifetime Annotations
1:33:23
Просмотров 215 тыс.
Rust's Alien Data Types 👽 Box, Rc, Arc
11:54
Просмотров 146 тыс.
Constructors Are Broken
18:16
Просмотров 108 тыс.
Async Rust Is A Bad Language | Prime Reacts
28:46
Просмотров 98 тыс.
The Secret to Rust Ownership: Rc vs. Arc
13:47
Просмотров 3,4 тыс.
why rust libraries may never exist.
7:26
Просмотров 258 тыс.
Teeth gadget every dentist should have 😬
00:20
Просмотров 975 тыс.