Great talk. Just one thing I wanted to point out: it's generally not a good idea to write functions to accept &String or &Vec, but rather to accept &str or &[T], which act as views without making any assumptions about the nature of what they point to. In the case of &[T], it works with both arrays and vectors, for example.
@@nishanth6403 Both &Vec and &[T] are const. The difference is the latter could put not only to a vector, but merely to a section of a vector, or even to a section of an array. It’s a slice.
Of all the very new languages that have come out lately (Kotlin, Go, Dart, Swift, etc.) Rust is definitely the most interesting one for me. Compile-time resource ownership bugs can be really annoying to find and fix, and although the C++ standard committee came out with the gsl library to help write code that is free of those kinds of bugs, having the constraints built into the language itself is obviously better.
well c++ compiler simply doesnt know. like he mentioned with unique and shared ptr. you can easily shoot yourself in the foot with cyclic shared ptr dependencies but it will compile fine
@@adamhenriksson6007 What he means is bugs caused by confusion of who owns some piece of data. For example if you have a pointer to something are you sure if it is your responsibility to free it or is there somewhere else with a pointer to it that should do that.? Rust checks for all kind of sill mistakes about using memory one might make: Using uninitialised data, use of memory after free, having multiple threads mutate data at, etc, etc. All checked at compile time, not ny asserts or crashes at run time.
Loving Rust. The borrow checker (Rusts most important feature) was so confusing to me the first time I tried learning the language. Then I learned copy and move semantics in Cpp and now Rust makes perfect sense lol.
Originally turtles were small physical robots shaped like a half bubble with wheels controlled by a (separate) computer. They looked a little like turtles and included a pen that could trace a path on large sheets of paper on the floor. Logo introduced a virtual screen-based version, also called a turtle.
Regarding C++, mutexes and RAII semantics, I had a small typo when creatiing the lock guard => there was no name. In C++ it is syntactically OK to instatiate objects without names. The trouble was, however, that having no name, its destructor was immediately called, so the guard was disposed just after creation, meaning it did not serve its purpose (normally it would be disposed at the end of the block) => no critical section. This obviously lead to run-time crushes when 2 or more threads were active. It took quite a while to spot the missing name in the code that seemingly looked perfectly OK.
Pretty good video for the audience he intended (C++ devs). I really hope people sit up and take notice of how the old tools open so many possibilities for subtle security issues, and how Rust takes that challenge to heart. The cyber world is literally under constant attack because there are insidious bugs that our compilers allow. It would be a much better place a generation from now if we started using Rust or its offspring on a regular basis. Not only is it very safe, but you also can cross compile native code without all the ugliness of C/C++ configure/autoconf/cmake, pick your poison, not to mention the litter of #ifdef macros everywhere in your code. Say goodbye to that. You won’t miss it.
26:05 calcPrimes and calcPrimesFixed: You are interested in the number of primes in a range. You should use std::async with std::launch::async. Put the resulting futures in a vector and sum them up with a loop. This would avoid all concurrency thus all problems. The power of Mutex is real, but there could have been a better example. A similar thing in C++ can and should be implemented and used. I totally like Rust for enforcing this, but it is not hopeless in C++ either. But then it will be still cheaper to catch this with compiler than with code guideline + review.
Logo and Mandelbrot sets… oh my. If you look up the original logo turtle, it was a robotic device attached to an umbilical cable that could draw on whatever it was placed upon. I like the bits of Haskell that Rust has stolen, especially if you can add traits to already existing structures. Guess I had better install Rust and try that.
4:48 Why did he said that Rust lacks compile-time/static polymorphism? Generic functions do just that. If type of the argument is known at compile time then specialized version would be used and only of type is unknown at compile-time (which means you explicitly used dyn) it would result in virtual call. The latter also happens if you used trait name as an argument type directly (i.e. function is not generic) so it is up to the programmer to choose what type of polymorphism should happen. Am I missing something? riptutorial.com/rust/example/4656/static-and-dynamic-dispatch
Because "static polymorphism" refers to method or function overloading, that is defining a function with the same name several times but with different arguments and the compiler then picking the matching overload. Rust doesn't support that.
He also says compile time polymorphism using templates. Initially, I thought he meant function overloading (not available in rust), but then he said "using templates" which is available in rust, with Generics as you said. Then, he also compares templates/generics later in the slide. I think he might have misspoken
so if you wanted to dynamically link Rust with something else (as Rust, so considering trait bounds, etc), the ABI will have to support trait bounds checking at runtime I guess? I know it's not possible at the moment, but if this will ever be possible, I can only think of some managed context (docker, nix, etc) where trait bounds are assured externally.
You cannot dynamically link a generic function, just like you cannot dynamically link eg. a template-only C++ library. In general if you dynamically link something you need it to have a stable ABI (and Rust’s ABI is not guaranteed to be stable, just like C++’s isn’t - even if some compilers do keep their ABI stable), so for dynamically linkable libraries it’s best to provide C API (Rust for that gives you `extern C` declarations for functions and `#[repr(C)]` attributes for types). If you create a Rust library that exposes C API, nothing stops you from dynamic linking.
43:08 Slide #16: Will not work for empty vectors. Same as C++, just identifying a bug. So this will result in a panic. Which concludes that index checking always happen when accessing vector elements in Rust. Which is a performance penalty for cases you know you are in the correct range.
There are "unsafe" methods in rust to access elements without performing bounds checking if you need them, and if you use iterators to sequentially access data, there is no bounds checking either. This "opt-in" behavior is better IMO, as you usually don't care about these micro-optimisations and could use the extra safety of bounds checking. Only when you really need the extra performance, you can opt into the faster unchecked accessor methods.
@@0phoff Furthermore some of these runtime checks are removed in release builds. For example integer overflows will crash your debug program - unless you explicitly declare that you want an operation to be able to overflow. But they won't in a release build. I think it's easy to miss how incredibly pragmatic the Rust developers are, despite their strict rules.
its not really possible to remove the existence of a bug like this. Rust does provide methods to make stuff like this easier, like the .get method which is an indexer that returns None when out of bounds. I would have the function return Option, then replace the indexing with: let mut largest = list.get(0)?; this automatically unwraps the item, but if the get method returned None, the whole function returns None early.
Rust is very different then c++, but it has plenty of advantages it seems. One thing I really do *not* like though : the constructor! Come on, they wanted to shorten every single keyword, but you have to use the new method explicitly to instantiate an object!!! That does not make sense!
You actually don't have to. If all the fields of a struct are accessible (i.e. they are marked "pub" for external types, or you are using them within the same module or crate (with pub(crate)), then you can instantiate a struct by simply initializing it with the field values, like "let my = MyStruct { field1: 0, field2: 1.0 };". If you happen to have two variables "field1" and "field2", you can shorten that to "let my = MyStruct { field1, field 2}". If you have a unit-like struct (a struct without fields), you can simply do "let my = MyStruct;". But, in general, it is best-practice to provide a "new" constructor (and/or implement the "Default" trait), as that allows you to hide the implementation details (the fields) of a struct, and only expose that which you want to be part of the public API.
25:00 Having multiple workers writing to a single data structure is a well explored problem. The implementation of the author is completely unrelated to C++. Good and bad solutions to such a problem can be implemented in Javascript, Go, C++, etc., basically almost any programming language that has a few basic tools implemented.
Not a silly question. The Allman style of braces with the brace on the next line is very popular and common in C/C++. Also, it makes more sense. It has the advantage that the braces line up so that your eye can more easily find the opening and closing of a block. With Rust, the opening brace is who knows where off to the right end of some line. Harder to pick out. You might want to depend on indentation but sometimes people get the indentation wrong. Further, people also use indentation when they wrap lines, so it takes you extra seconds to figure out if you're looking at a new block or just a line wrap. Unfortunately Rust has chosen to enforce their particular favorite code style on everyone else. (At least if they are going to do that they should have picked Allman style.) When I complain about this I am told that the auto-formatter can be configured. Which is true in theory. You're supposed to be able to choose brace-on-the-next-line style. But many configuration options are considered not stable and I have still not been able to get it to work.
The vector example around 31:20 is not equivalent to C++. He's allocating the vector on heap in Rust but on stack in C++ which would affect performance. Also in real life a C++ programmer would just resize the vector to the same length as the number of threads and let each thread know its own index thus eliminating the need for a mutex alltogether.
You cannot allocate a vector's actual element storage on the stack; neither in C++ nor in Rust. Since a vector needs to be able to resize when it runs out of space, the stack won't do. The C++ and Rust examples are in fact, identical. Rust, like C++, stores the vector metadata on the stack, but the actual elements on the heap. (This assumes normal use; with some crazy allocator hackery, you could probably contort the vector to store its elements on the stack too, but that's so far outside normal use that it's not worth considering.) Also, the example is obviously contrived to illustrate a point. By using exclusive locking you lose most of the gain multi-threading would provide you anyway, so of course you wouldn't do it this way in a real solution.
@@fhajji And neither would you need to in rust, because it also has parallel algorithms and iterators etc. But the point was not about thread and vector but about guaranteed freedom from data races, regardless of how complex the application gets. Just consider the man-years or centuries wasted on reviewing, debugging, analyzing and reproducing data races in everything but the most trivial C++ applications and the effect on the user's data and operations...
The whole stuff about the enums is 'stolen' from functional languages. Same for immutable data. Optional values, pattern matching? Likewise. All this is for instance present in F#.
I prefer to think of "inspired" rather than "stolen". Presumably you think these are desirable features in a language. So it's good to seem them come to a language that can be used for systems programming, requiring no run-time system/virtual machine or garbage collector. A language that can be used from micro-controllers with limited memory and no operating system all the way up to web servers and everything else. A language to do things that would traditionally have to be done in C/C++ for performance reasons, like writing a VM, but with far more emphasis on correctness and memory safety. Rust is truly remarkable and unique in that respect.
@@heater5979 yes, this far more emphasis on correctness and memory safety is an important feature of Rust and one that distinguishes it from most other programming languages. You could achieve similar with C++'s unique_ptr, but the syntax is ugly and verbose, plus C++ would not guarantee anything: you could still use raw pointers etc.
all of the math operations are implemented as associated methods, like for example .sqrt(), .max(), .hypot(), .pow(), .ipow(). You can call them as non associated if you want though, like i32::max(num1, num2)
I think most C++ programmers would hate Rust... unless they have also programmed in Erlang, in which case they'd love it. Point is that Rust aims to do some great things, but they are somewhat mixed and unless a programmer has actually needed them, which is rarely the case, they would not like all the hassle. From a C++ programmer point of view Rust is a set of misunderstood "hearsay good practices" at a high price.
That's an easy impression to get - but it's actually not at all a good description of Rust. A more fitting (but still slightly hyperbolic) description would be: Rust makes sane choices the default, you can break out to insanity at any point but you have to be explicit about it. You can create all the same stupid bugs that every C++ project has - but you won't do so by accident.
I know that I'M responding to an old comment here, but maybe you never got your answer or someone else scrolls through this comment section and finds this. As Pavel explained a little earlier in the talk, when you pass a variable to a function in Rust, you give up its ownership. The new owner of the data can decide whether it wants to treat it as mutable or not. The previous owner doesn't care. And that's what happens in the code example. The data variable is indeed declared as immutable, but it's immediately passed to Mutex::new(). The Mutex is now the new owner of the Vec and it can mutate it if it wants. Not because Mutex is special, but because of how ownership works.
Simon WoodburyForget Thats bullshit, dont spread wrong information. Structs and classes in C++ are identical the only difference is members of structs are public instead of private by default.
And you can't store a reference type in a std::variant (or std::optional) since the contents of a variant have to be zero-initializable (which references are assumed to never be)
@@valshaped i didn't say the rust ones weren't better....just that he should have at least mentioned the C++ variant when discussing rust enums, if only to say they're inferior.
from what i see it is defenitly slower than c++ specialy in complex projects(Game engine, renderer, ...) and i'm not a fan of restricted access. ALSO: VS CODE IS NOT AN IDE IT IS AN EDITOR. 28:25
rust is not slower than c++. its just a slightly different style, and there are definitely plenty of tools for whatever youre looking for in unrestricted access. It's not restricted access; it's guaranteed safe access. All of these ownership and borrowing checks are done at compile time, therefore have zero effect on performance. Rust and c++ have the mindset of zero overhead abstractions in common, except rust has learned from the mistakes of c++, implements these abstractions in modern, much more flexible ways and doesnt have 40 years of legacy features. From what i've heard, the rust compiler is actually better at optimizing than c++ is, because it has much more guarantees of which things can change which things and such. I dont have any specific proof, though. Sure, vs code might be advertised as an editor or something, but it can act extremely similar to an actual IDE with the right extensions which in this case is rust analyzer, so I think its fair to call it an IDE sometimes.
Very informative talk. But the C++ thread example is simply bad programming. You explicitly share the vector between threads and then "complain" that it creates race conditions. Of course it does, because you told it to do exactly that! Then saying that the mutex is not related in any way to the vector and claiming it is bad. Of course they are not related, you wrote it that way! You want to tie them together, tie them, no one is stopping you from creating "multithreaded_vector". You used the exact same "fix" in the rust to make it correct there too. I get you want to show Rust as the better option but writing bad C++ is not the way to do it. The same goes for the earlier example with auto& val = vec[0]. IF you read the documentation, it clearly states any non-const operation might invalidate such references. Vector was simply designed to behave such way, you want permanent storage? Reserve the size or use a different container. I guess, my point is to use always use the right tools for the job. C++ has them, I'm sure Rust too. Using the wrong ones can make any language look bad.
Agreed. When people cherrypick or make strawman arguments about why a language is "better" it always puts me off. I'm watching this lecture because I want to see what rust has to offer without going through baby's first rust program tutorials. You already have my money (figuratively) , you don't need to try and trick me.
the point he was making is that the compiler makes you not write it that way, also those kinds of errors are easy to see when there are only a few lines of code, but they become problematic when you forget to do something in some other code, the advantage is that rust makes sure that those errors are caught at compile time and not in production where it can cost the company lots of money.
You missed the point. The point is, that C++ lets you write and compile something as monumentally stupid as those examples, without any indication of an issue. Rust compiler will reject such code at compile time, actually forcing you do fix it. That is the feature he was trying to demonstrate.
Yeah, you completely missed the point. Consider a complex project which many people are working on. It's not that people deliberately get multithreading wrong, but that they make mistakes. It might not even be their own but a combination of the work of different people resulting in subtle multithreading bugs ... that can lead to data corruption, loss, crashes. Rust prevents this in the first place. You don't have to spend hours or days in reviews and bug hunting because if it compiles, then there cannot be a data race. And your conclusion is valid: if you want to be certain then C++ is only the right tool for trivial programs. Rust is a toolbox, C++ is a hammer with rusty nails sticking out of its handle.
@@xnoreq Honestly, what? Have you even read what I wrote? I said writing bad C++ is not a good way to criticize the language as a whole. The comparison made by the author is simply not fair. He intentionally wrote unsafe C++ and then complained it is unsafe. Well, duh! No one stops you or him from writing the code properly - protecting the vector with a mutex. Not sharing it in the first place and return local results. Using some library with thread-safe containers. Again, using `std::vector` for what is it not designed for is not a valid argument to criticize the language. Simple as that. C++ is a toolbox exactly because it does not restrict you in any way. Do you need fast single-threaded continuous container. You cannot do much better than vector. Do you need something else or perhaps write a custom one specifically based on your needs. You can! Perhaps this is completely different mindset for you, but I want the language to allow me to do what I want, no what I am allowed to. I consider it a disadvantage if Rust forbids you from sharing mutable references if that is a case. I do not have much experience with the language. But I think it is good default behaviour. Has C++ more ways to shoot yourself in the foot? Sure, that is not bad because it comes from the expressiveness of the language. Could the threading library be better? Sure, feel free to contribute to make it better. Is C++ safe now? Not at all, but it is going there. E.g. smart pointers, move semantics help a lot with memory issues, but they do NOT restrict you if you do not want to. Could the compile time support be better? Certainly and again it's getting there with static_assert, constexpr, and Concepts now. "if you want to be certain then C++ is only the right tool for trivial programs." What an immature thing to say. You know it's not true, but go have your language-flame-war-for-stroking-your-ego somewhere else.
@@notforvideoschannel Well it's low-level programming so no, there are a lot of similarities. But yeah you probably won't be as efficient from the get-go lol.
Two things: 1. Unnecessary c++ bashing. We, the C++ devs, are already here, we already know about the problems Rust solves at least in broad terms. The c++ bashing feels just out of place here. 2. This is supposed to be a talk for people that know C++, not for people that have barely touched C++ and have basically no clue what's going on anyway but it treats its audience as pretty much completely incompetent. Rust elitarism will only turn everyone else away. Not pull people towards Rust. And I am not talking about the merits of the actual language which are pretty much undeniable, but the conceited attitude of Rust advocates. Edit: Beyond that, it's actually kind of embarrassing that there are plain mistakes in his C++. And I am not talking about some minor unimportant stuff that's not really relevant. For example, the C++ compiler does NOT allow compilation with a missing operator implementation. I have no idea where this guy got that idea. C++ is a compiled language and what he proposes is literally not possible in a classic compiled language without some scripting language style dynamic typing workaround. It's not C++ compilers being smart about this. It's literally impossible.
Yeah, who wants to be prevented from making silly mistakes when you can discover them a few weeks or months down the line instead when your program suddenly has a data-race you couldn't foresee? That's way more fun than having the Rust compiler not even letting you make the mistake in the first place! For real though, "yikes" is not a very good criticism. :P
17:00 Compile time checking is better than runtime. So why make up a fake strawman argument saying "the error isn't easy to find". If you really can't debug a simple error like that, I don't care what language you use, you're a bad, or at least very inexperienced, developer. Look at the callstack and find the call from your code. If you have a runtime failure in any language where you're calling code that isn't your own, this will be the case.
Because it's neither fake nor a strawman. Only an inexperienced developer would say that. Bugs in C++ can lead to subtle memory corruption. In the worst case, this corrupts user data and results silently, without crashing. In the best case, it crashes. But if it crashes, the point of the crash may not be the root cause of the corruption. In fact, it can be completely unrelated. It seems to me you've never seen complex applications that crash due to data races that are incredibly hard to analyze or reproduce.
@@xnoreq Considering I'm the person everyone turns to when there is a bug or a crash, and I've only had a problem tracking down one issue - ever- and its in a system that would probably blow your mind, maybe I'm just that much better than you. PS. I'm also pretty confident I fixed that issue, since I haven't seen it in a long time.
@@khatdubell Clearly, you are a god, or someone with an ego so big that he felt attacked and saw the need to defend himself instead of dealing with the argument ... in a non-fallacious way. And even if you actually were, it'd be a bit like the 100 year-old chain smoker telling people that smoking isn't unhealthy. This is also why I will not further engage in a discussion about the actual complexity of the applications you're working with. The fact is that your initial argument is actually the straw man and based on what seems to be a naive or inexperienced view of what can go wrong in large, complex and often legacy C++ applications especially when multi-threaded.
@@xnoreq there was no argument do deal with. You're the one who decided because i don't have difficulty in dealing with issues i must have never seen a complex system. Sorry if you have difficulties.
@@khatdubell Then don't get into Rust. Please, whatever you do, don't pollute the ecosystem with people that have such confidence issues. We're so happy without you.
"Rust is really all about keeping things short" he says while I look at my print!("Enter the design value for the measure: "); std::io::stdout().flush().unwrap(); let mut input = String::new(); match std::io::stdin().read_line(&mut input) { Ok(_) => (), Err(_) => { println!("Couldn't read input"); } }; let measure = match input.trim().parse::() { Ok(f) => f, Err(_) => { println!("Not a float number"); return Err(()); } }; Or in C++: std::cout >> "Enter the design value for the measure: "; double measure; std::cin >> measure; I know the C++ doesn't have error handing for reading the user input and for the float, but C++ 1. compiles 2. works like that with expected inputs. For Rust there is no option to skip that wall of text. Did he have to bring up LOGO!... Just today I returned an automation assignment that was done in Siemens LOGO!Soft Comfort which wasn't my favourite moments of "coding".
Great talk. Just one thing I wanted to point out: it's generally not a good idea to write functions to accept &String or &Vec, but rather to accept &str or &[T], which act as views without making any assumptions about the nature of what they point to. In the case of &[T], it works with both arrays and vectors, for example.
So const references ?
@@nishanth6403 Both &Vec and &[T] are const. The difference is the latter could put not only to a vector, but merely to a section of a vector, or even to a section of an array. It’s a slice.
Of all the very new languages that have come out lately (Kotlin, Go, Dart, Swift, etc.) Rust is definitely the most interesting one for me. Compile-time resource ownership bugs can be really annoying to find and fix, and although the C++ standard committee came out with the gsl library to help write code that is free of those kinds of bugs, having the constraints built into the language itself is obviously better.
Compile-time resource ownership bugs?
well c++ compiler simply doesnt know. like he mentioned with unique and shared ptr. you can easily shoot yourself in the foot with cyclic shared ptr dependencies but it will compile fine
@@adamhenriksson6007 What he means is bugs caused by confusion of who owns some piece of data. For example if you have a pointer to something are you sure if it is your responsibility to free it or is there somewhere else with a pointer to it that should do that.? Rust checks for all kind of sill mistakes about using memory one might make: Using uninitialised data, use of memory after free, having multiple threads mutate data at, etc, etc. All checked at compile time, not ny asserts or crashes at run time.
@@Heater-v1.0.0 Ye most likely, but the terminology seemed both very confusing and oddly specific at the same time.
Loving Rust. The borrow checker (Rusts most important feature) was so confusing to me the first time I tried learning the language. Then I learned copy and move semantics in Cpp and now Rust makes perfect sense lol.
Absolutely. Rust rewrote my brain and i'm much better at writing c++ thanks to Rust lol
Originally turtles were small physical robots shaped like a half bubble with wheels controlled by a (separate) computer. They looked a little like turtles and included a pen that could trace a path on large sheets of paper on the floor. Logo introduced a virtual screen-based version, also called a turtle.
til
Regarding C++, mutexes and RAII semantics, I had a small typo when creatiing the lock guard => there was no name. In C++ it is syntactically OK to instatiate objects without names. The trouble was, however, that having no name, its destructor was immediately called, so the guard was disposed just after creation, meaning it did not serve its purpose (normally it would be disposed at the end of the block) => no critical section. This obviously lead to run-time crushes when 2 or more threads were active. It took quite a while to spot the missing name in the code that seemingly looked perfectly OK.
Great video for C++ devs who look for some opportunity to get into Rust.
Pretty good video for the audience he intended (C++ devs). I really hope people sit up and take notice of how the old tools open so many possibilities for subtle security issues, and how Rust takes that challenge to heart. The cyber world is literally under constant attack because there are insidious bugs that our compilers allow. It would be a much better place a generation from now if we started using Rust or its offspring on a regular basis.
Not only is it very safe, but you also can cross compile native code without all the ugliness of C/C++ configure/autoconf/cmake, pick your poison, not to mention the litter of #ifdef macros everywhere in your code. Say goodbye to that. You won’t miss it.
Liar. You are a zealot!
Ifndef macros were deprecated and pragma once i think is the new thing, no?
As a c++ dev, I think he really makes a good job. Thanks!
26:05 calcPrimes and calcPrimesFixed: You are interested in the number of primes in a range. You should use std::async with std::launch::async. Put the resulting futures in a vector and sum them up with a loop. This would avoid all concurrency thus all problems. The power of Mutex is real, but there could have been a better example. A similar thing in C++ can and should be implemented and used. I totally like Rust for enforcing this, but it is not hopeless in C++ either. But then it will be still cheaper to catch this with compiler than with code guideline + review.
Logo and Mandelbrot sets… oh my. If you look up the original logo turtle, it was a robotic device attached to an umbilical cable that could draw on whatever it was placed upon. I like the bits of Haskell that Rust has stolen, especially if you can add traits to already existing structures. Guess I had better install Rust and try that.
This was so fucking good - Rust does so many things right, hell probably most things!
@@arian5126 Can you elaborate
@@arian5126 you have no unbiased proof.
Thank you Pavel! Excellent talk!
Very great talk. Thanks for sharing.
4:48 Why did he said that Rust lacks compile-time/static polymorphism? Generic functions do just that. If type of the argument is known at compile time then specialized version would be used and only of type is unknown at compile-time (which means you explicitly used dyn) it would result in virtual call. The latter also happens if you used trait name as an argument type directly (i.e. function is not generic) so it is up to the programmer to choose what type of polymorphism should happen. Am I missing something?
riptutorial.com/rust/example/4656/static-and-dynamic-dispatch
Because "static polymorphism" refers to method or function overloading, that is defining a function with the same name several times but with different arguments and the compiler then picking the matching overload.
Rust doesn't support that.
@@xnoreq That is rather peculiar definition of "static polymorphism". Ok then.
@@IlyaDenisov That's compile time polymorphism. Different.
He also says compile time polymorphism using templates. Initially, I thought he meant function overloading (not available in rust), but then he said "using templates" which is available in rust, with Generics as you said. Then, he also compares templates/generics later in the slide. I think he might have misspoken
Nice video, i'm starting to love Rust, TNX
If I don't get to think "Is this well-defined behavior? Sh*t I forgot again. Oh! Why do I do this to myself?" every 10 minutes, then it's not for me.
if that and debugging for obscure memory bugs is your thing then go for c++ lol
so if you wanted to dynamically link Rust with something else (as Rust, so considering trait bounds, etc), the ABI will have to support trait bounds checking at runtime I guess? I know it's not possible at the moment, but if this will ever be possible, I can only think of some managed context (docker, nix, etc) where trait bounds are assured externally.
You cannot dynamically link a generic function, just like you cannot dynamically link eg. a template-only C++ library.
In general if you dynamically link something you need it to have a stable ABI (and Rust’s ABI is not guaranteed to be stable, just like C++’s isn’t - even if some compilers do keep their ABI stable), so for dynamically linkable libraries it’s best to provide C API (Rust for that gives you `extern C` declarations for functions and `#[repr(C)]` attributes for types). If you create a Rust library that exposes C API, nothing stops you from dynamic linking.
Great presentation. Thank you.
I can't see what you're trying to express that the Rust external libraries source is better than NuGet but the rest was interesting.
thank you 👍
43:08 Slide #16: Will not work for empty vectors. Same as C++, just identifying a bug. So this will result in a panic. Which concludes that index checking always happen when accessing vector elements in Rust. Which is a performance penalty for cases you know you are in the correct range.
There are "unsafe" methods in rust to access elements without performing bounds checking if you need them, and if you use iterators to sequentially access data, there is no bounds checking either. This "opt-in" behavior is better IMO, as you usually don't care about these micro-optimisations and could use the extra safety of bounds checking. Only when you really need the extra performance, you can opt into the faster unchecked accessor methods.
@@0phoff Furthermore some of these runtime checks are removed in release builds. For example integer overflows will crash your debug program - unless you explicitly declare that you want an operation to be able to overflow. But they won't in a release build.
I think it's easy to miss how incredibly pragmatic the Rust developers are, despite their strict rules.
its not really possible to remove the existence of a bug like this. Rust does provide methods to make stuff like this easier, like the .get method which is an indexer that returns None when out of bounds.
I would have the function return Option, then replace the indexing with:
let mut largest = list.get(0)?;
this automatically unwraps the item, but if the get method returned None, the whole function returns None early.
Rust is very different then c++, but it has plenty of advantages it seems.
One thing I really do *not* like though : the constructor!
Come on, they wanted to shorten every single keyword, but you have to use the new method explicitly to instantiate an object!!! That does not make sense!
You actually don't have to.
If all the fields of a struct are accessible (i.e. they are marked "pub" for external types, or you are using them within the same module or crate (with pub(crate)), then you can instantiate a struct by simply initializing it with the field values, like "let my = MyStruct { field1: 0, field2: 1.0 };". If you happen to have two variables "field1" and "field2", you can shorten that to "let my = MyStruct { field1, field 2}".
If you have a unit-like struct (a struct without fields), you can simply do "let my = MyStruct;".
But, in general, it is best-practice to provide a "new" constructor (and/or implement the "Default" trait), as that allows you to hide the implementation details (the fields) of a struct, and only expose that which you want to be part of the public API.
You don't have to call it new, or even you don't have to have "constructor" at all, that s the beauty of the Rust, explicitness and freedom
25:00 Having multiple workers writing to a single data structure is a well explored problem. The implementation of the author is completely unrelated to C++. Good and bad solutions to such a problem can be implemented in Javascript, Go, C++, etc., basically almost any programming language that has a few basic tools implemented.
It has a lot of similar features to Scala.
"Not everybody likes Microsoft." XD The understatement of the century!
can i still place the curly brace into next line? come on don't be ridiculous like go
Yes, you can.
what a silly question
Not a silly question. The Allman style of braces with the brace on the next line is very popular and common in C/C++. Also, it makes more sense. It has the advantage that the braces line up so that your eye can more easily find the opening and closing of a block. With Rust, the opening brace is who knows where off to the right end of some line. Harder to pick out.
You might want to depend on indentation but sometimes people get the indentation wrong. Further, people also use indentation when they wrap lines, so it takes you extra seconds to figure out if you're looking at a new block or just a line wrap.
Unfortunately Rust has chosen to enforce their particular favorite code style on everyone else. (At least if they are going to do that they should have picked Allman style.) When I complain about this I am told that the auto-formatter can be configured. Which is true in theory. You're supposed to be able to choose brace-on-the-next-line style. But many configuration options are considered not stable and I have still not been able to get it to work.
Yeah, you can put it wherever. You can put everything into one line if you really want.
where is the slide?
The vector example around 31:20 is not equivalent to C++. He's allocating the vector on heap in Rust but on stack in C++ which would affect performance. Also in real life a C++ programmer would just resize the vector to the same length as the number of threads and let each thread know its own index thus eliminating the need for a mutex alltogether.
You cannot allocate a vector's actual element storage on the stack; neither in C++ nor in Rust. Since a vector needs to be able to resize when it runs out of space, the stack won't do. The C++ and Rust examples are in fact, identical. Rust, like C++, stores the vector metadata on the stack, but the actual elements on the heap. (This assumes normal use; with some crazy allocator hackery, you could probably contort the vector to store its elements on the stack too, but that's so far outside normal use that it's not worth considering.)
Also, the example is obviously contrived to illustrate a point. By using exclusive locking you lose most of the gain multi-threading would provide you anyway, so of course you wouldn't do it this way in a real solution.
Is C++, you won't even use std::thread explicitly in this case, when you can use parallel version of std::for_each (or tbb::for_each, ...).
@@fhajji And neither would you need to in rust, because it also has parallel algorithms and iterators etc.
But the point was not about thread and vector but about guaranteed freedom from data races, regardless of how complex the application gets.
Just consider the man-years or centuries wasted on reviewing, debugging, analyzing and reproducing data races in everything but the most trivial C++ applications and the effect on the user's data and operations...
The whole stuff about the enums is 'stolen' from functional languages. Same for immutable data. Optional values, pattern matching? Likewise. All this is for instance present in F#.
I prefer to think of "inspired" rather than "stolen".
Presumably you think these are desirable features in a language. So it's good to seem them come to a language that can be used for systems programming, requiring no run-time system/virtual machine or garbage collector. A language that can be used from micro-controllers with limited memory and no operating system all the way up to web servers and everything else. A language to do things that would traditionally have to be done in C/C++ for performance reasons, like writing a VM, but with far more emphasis on correctness and memory safety. Rust is truly remarkable and unique in that respect.
@@heater5979 yes, this far more emphasis on correctness and memory safety is an important feature of Rust and one that distinguishes it from most other programming languages. You could achieve similar with C++'s unique_ptr, but the syntax is ugly and verbose, plus C++ would not guarantee anything: you could still use raw pointers etc.
doc.rust-lang.org/reference/influences.html
3:15 What associated methods Rust has for primitive types? I can't find anything about it in the documentation.
all of the math operations are implemented as associated methods, like for example .sqrt(), .max(), .hypot(), .pow(), .ipow().
You can call them as non associated if you want though, like i32::max(num1, num2)
I think most C++ programmers would hate Rust... unless they have also programmed in Erlang, in which case they'd love it. Point is that Rust aims to do some great things, but they are somewhat mixed and unless a programmer has actually needed them, which is rarely the case, they would not like all the hassle. From a C++ programmer point of view Rust is a set of misunderstood "hearsay good practices" at a high price.
Rust now also have unions
you have to use the unsafe keyword to access data in them, but yeah seems like they exist now
So Rust is like the Mandalorian? "This is the way" "You can't do that, that's against the rules"
i didn't teach my self rust, the compiler did
@@miqbalrofikurrahman9486
Indeed .
You don't know why this code doesn't work ?
Compiler will tell you .
That's an easy impression to get - but it's actually not at all a good description of Rust.
A more fitting (but still slightly hyperbolic) description would be: Rust makes sane choices the default, you can break out to insanity at any point but you have to be explicit about it.
You can create all the same stupid bugs that every C++ project has - but you won't do so by accident.
at 31:28, shouldn't line 25 be: let mut data = Vec::new(); , instead of let data = Vec:new(); ?
Mutex is special. I don't quite understand it myself, but the reason the code works is mutex, if you want to google your way to the answer.
I know that I'M responding to an old comment here, but maybe you never got your answer or someone else scrolls through this comment section and finds this.
As Pavel explained a little earlier in the talk, when you pass a variable to a function in Rust, you give up its ownership. The new owner of the data can decide whether it wants to treat it as mutable or not. The previous owner doesn't care. And that's what happens in the code example.
The data variable is indeed declared as immutable, but it's immediately passed to Mutex::new(). The Mutex is now the new owner of the Vec and it can mutate it if it wants. Not because Mutex is special, but because of how ownership works.
@@Betacak3 makes sense, thanks
That's new how are classes and structs the same?
In C++ classes and structs have exactly the same functionality except that struct members are public by default, with classes they are private.
@@20thCB Wait, structs don't have vtables and such right? Are you sure they are identical?
@@sander_bouwhuis yeah, no difference except for visibility
Simon WoodburyForget Thats bullshit, dont spread wrong information. Structs and classes in C++ are identical the only difference is members of structs are public instead of private by default.
Seems like the presenter hasn't heard oof std::variant in c++17 - which seems mroe or less the same as rust enums
Except the variants are unnamed and there's no language support for pattern matching
And you can't store a reference type in a std::variant (or std::optional) since the contents of a variant have to be zero-initializable (which references are assumed to never be)
@@valshaped i didn't say the rust ones weren't better....just that he should have at least mentioned the C++ variant when discussing rust enums, if only to say they're inferior.
from what i see it is defenitly slower than c++ specialy in complex projects(Game engine, renderer, ...) and i'm not a fan of restricted access.
ALSO: VS CODE IS NOT AN IDE IT IS AN EDITOR. 28:25
rust is not slower than c++. its just a slightly different style, and there are definitely plenty of tools for whatever youre looking for in unrestricted access. It's not restricted access; it's guaranteed safe access. All of these ownership and borrowing checks are done at compile time, therefore have zero effect on performance.
Rust and c++ have the mindset of zero overhead abstractions in common, except rust has learned from the mistakes of c++, implements these abstractions in modern, much more flexible ways and doesnt have 40 years of legacy features.
From what i've heard, the rust compiler is actually better at optimizing than c++ is, because it has much more guarantees of which things can change which things and such. I dont have any specific proof, though.
Sure, vs code might be advertised as an editor or something, but it can act extremely similar to an actual IDE with the right extensions which in this case is rust analyzer, so I think its fair to call it an IDE sometimes.
Sir Talkalot.
Very informative talk. But the C++ thread example is simply bad programming. You explicitly share the vector between threads and then "complain" that it creates race conditions. Of course it does, because you told it to do exactly that! Then saying that the mutex is not related in any way to the vector and claiming it is bad. Of course they are not related, you wrote it that way! You want to tie them together, tie them, no one is stopping you from creating "multithreaded_vector". You used the exact same "fix" in the rust to make it correct there too. I get you want to show Rust as the better option but writing bad C++ is not the way to do it.
The same goes for the earlier example with auto& val = vec[0]. IF you read the documentation, it clearly states any non-const operation might invalidate such references. Vector was simply designed to behave such way, you want permanent storage? Reserve the size or use a different container.
I guess, my point is to use always use the right tools for the job. C++ has them, I'm sure Rust too. Using the wrong ones can make any language look bad.
Agreed.
When people cherrypick or make strawman arguments about why a language is "better" it always puts me off.
I'm watching this lecture because I want to see what rust has to offer without going through baby's first rust program tutorials. You already have my money (figuratively) , you don't need to try and trick me.
the point he was making is that the compiler makes you not write it that way, also those kinds of errors are easy to see when there are only a few lines of code, but they become problematic when you forget to do something in some other code, the advantage is that rust makes sure that those errors are caught at compile time and not in production where it can cost the company lots of money.
You missed the point. The point is, that C++ lets you write and compile something as monumentally stupid as those examples, without any indication of an issue. Rust compiler will reject such code at compile time, actually forcing you do fix it. That is the feature he was trying to demonstrate.
Yeah, you completely missed the point. Consider a complex project which many people are working on. It's not that people deliberately get multithreading wrong, but that they make mistakes. It might not even be their own but a combination of the work of different people resulting in subtle multithreading bugs ... that can lead to data corruption, loss, crashes.
Rust prevents this in the first place. You don't have to spend hours or days in reviews and bug hunting because if it compiles, then there cannot be a data race.
And your conclusion is valid: if you want to be certain then C++ is only the right tool for trivial programs.
Rust is a toolbox, C++ is a hammer with rusty nails sticking out of its handle.
@@xnoreq Honestly, what? Have you even read what I wrote? I said writing bad C++ is not a good way to criticize the language as a whole. The comparison made by the author is simply not fair. He intentionally wrote unsafe C++ and then complained it is unsafe. Well, duh! No one stops you or him from writing the code properly - protecting the vector with a mutex. Not sharing it in the first place and return local results. Using some library with thread-safe containers.
Again, using `std::vector` for what is it not designed for is not a valid argument to criticize the language. Simple as that.
C++ is a toolbox exactly because it does not restrict you in any way. Do you need fast single-threaded continuous container. You cannot do much better than vector.
Do you need something else or perhaps write a custom one specifically based on your needs. You can!
Perhaps this is completely different mindset for you, but I want the language to allow me to do what I want, no what I am allowed to.
I consider it a disadvantage if Rust forbids you from sharing mutable references if that is a case. I do not have much experience with the language. But I think it is good default behaviour.
Has C++ more ways to shoot yourself in the foot? Sure, that is not bad because it comes from the expressiveness of the language. Could the threading library be better? Sure, feel free to contribute to make it better. Is C++ safe now? Not at all, but it is going there. E.g. smart pointers, move semantics help a lot with memory issues, but they do NOT restrict you if you do not want to. Could the compile time support be better? Certainly and again it's getting there with static_assert, constexpr, and Concepts now.
"if you want to be certain then C++ is only the right tool for trivial programs."
What an immature thing to say. You know it's not true, but go have your language-flame-war-for-stroking-your-ego somewhere else.
No thanks, I spent a lot of time learning C++. I don't want to lose everything.
Lol what
@@azertycraftgaming My C++ experience and knowledge will be useless if I switch to Rust. Right?
@@notforvideoschannel Well it's low-level programming so no, there are a lot of similarities. But yeah you probably won't be as efficient from the get-go lol.
Two things:
1. Unnecessary c++ bashing. We, the C++ devs, are already here, we already know about the problems Rust solves at least in broad terms. The c++ bashing feels just out of place here.
2. This is supposed to be a talk for people that know C++, not for people that have barely touched C++ and have basically no clue what's going on anyway but it treats its audience as pretty much completely incompetent.
Rust elitarism will only turn everyone else away. Not pull people towards Rust. And I am not talking about the merits of the actual language which are pretty much undeniable, but the conceited attitude of Rust advocates.
Edit:
Beyond that, it's actually kind of embarrassing that there are plain mistakes in his C++. And I am not talking about some minor unimportant stuff that's not really relevant. For example, the C++ compiler does NOT allow compilation with a missing operator implementation. I have no idea where this guy got that idea. C++ is a compiled language and what he proposes is literally not possible in a classic compiled language without some scripting language style dynamic typing workaround. It's not C++ compilers being smart about this. It's literally impossible.
yikes, i dont like rust now
Yeah, who wants to be prevented from making silly mistakes when you can discover them a few weeks or months down the line instead when your program suddenly has a data-race you couldn't foresee? That's way more fun than having the Rust compiler not even letting you make the mistake in the first place!
For real though, "yikes" is not a very good criticism. :P
No. I do not need stupid unsafe shit like Rust. CVE hazards
way too many programming languages these days
there are many toy programming languages, but there will always be c c++ and assembly :)
17:00
Compile time checking is better than runtime.
So why make up a fake strawman argument saying "the error isn't easy to find".
If you really can't debug a simple error like that, I don't care what language you use, you're a bad, or at least very inexperienced, developer.
Look at the callstack and find the call from your code.
If you have a runtime failure in any language where you're calling code that isn't your own, this will be the case.
Because it's neither fake nor a strawman. Only an inexperienced developer would say that.
Bugs in C++ can lead to subtle memory corruption. In the worst case, this corrupts user data and results silently, without crashing.
In the best case, it crashes. But if it crashes, the point of the crash may not be the root cause of the corruption. In fact, it can be completely unrelated.
It seems to me you've never seen complex applications that crash due to data races that are incredibly hard to analyze or reproduce.
@@xnoreq
Considering I'm the person everyone turns to when there is a bug or a crash, and I've only had a problem tracking down one issue - ever- and its in a system that would probably blow your mind, maybe I'm just that much better than you.
PS.
I'm also pretty confident I fixed that issue, since I haven't seen it in a long time.
@@khatdubell Clearly, you are a god, or someone with an ego so big that he felt attacked and saw the need to defend himself instead of dealing with the argument ... in a non-fallacious way.
And even if you actually were, it'd be a bit like the 100 year-old chain smoker telling people that smoking isn't unhealthy.
This is also why I will not further engage in a discussion about the actual complexity of the applications you're working with.
The fact is that your initial argument is actually the straw man and based on what seems to be a naive or inexperienced view of what can go wrong in large, complex and often legacy C++ applications especially when multi-threaded.
@@xnoreq there was no argument do deal with.
You're the one who decided because i don't have difficulty in dealing with issues i must have never seen a complex system.
Sorry if you have difficulties.
@@khatdubell Then don't get into Rust. Please, whatever you do, don't pollute the ecosystem with people that have such confidence issues. We're so happy without you.
"Rust is really all about keeping things short" he says while I look at my
print!("Enter the design value for the measure: ");
std::io::stdout().flush().unwrap();
let mut input = String::new();
match std::io::stdin().read_line(&mut input) {
Ok(_) => (),
Err(_) => {
println!("Couldn't read input");
}
};
let measure = match input.trim().parse::() {
Ok(f) => f,
Err(_) => {
println!("Not a float number");
return Err(());
}
};
Or in C++:
std::cout >> "Enter the design value for the measure: ";
double measure;
std::cin >> measure;
I know the C++ doesn't have error handing for reading the user input and for the float, but C++ 1. compiles 2. works like that with expected inputs. For Rust there is no option to skip that wall of text.
Did he have to bring up LOGO!... Just today I returned an automation assignment that was done in Siemens LOGO!Soft Comfort which wasn't my favourite moments of "coding".
you can propagate errors in rust with "?". it makes code much cleaner. also, you don't need to flush after println