All Rust features explained

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
if you've ever struggled to understand Russ features or how they work together this video is for you rust has many unbelievably genius features but these features aren't exactly unique to rust in fact Russ deliberately borrows these great features from many other languages and combines them into a single Masterpiece understanding where Russ's most important features come from and how rust has built on top of them is critical to use rust effectively so in this video I'll explain rust's most popular features how other languages like C plus Haskell and JavaScript influence them and how Russ combine those features and built on top of them to become the most loved language of our time note that these features are sorted by complexity so stick around till the end for rust's most advanced features this video is part of a series for the upcoming official launch of my rust developer Bootcamp The all-in-one rust learning program you've all been asking for the exact official launch date will be determined very soon to join the waitlist pause this video right now and visit let's get rusty dot com slash boot camp first let's talk about an amazing feature Russ took from C plus plus the principle of zero cost abstractions this principle can be summarized with the following phrase what you don't use you don't pay for and what you do use you couldn't have hand coded any better this means that high level language abstractions like generics and collections should not impose any runtime overhead or performance penalties compared to code using low-level abstractions like loops and counters in the C plus plus example we create a vector of integers and then use a for Loop to find the greatest element in the vector in this example we have to do Loop initialization condition checking and element comparison making a less readable and more prone to errors by using the iterator abstraction the code becomes a lot simpler now we just have to call the max element function the iterator abstraction encapsulates iteration and comparison logic making the code cleaner more concise and less error prone without sacrificing performance here's a how we would write the same code in Rust first we turn the vector into an iterator by calling the itter method and then we find the greatest element by calling the max method in this example we're actually using a few zero cost abstractions in Rust the first one being the iterator abstraction the second one is the option enum and the third is pattern matching the beautiful thing about rust is that it builds on top of the zero cost abstraction principle by further emphasizing memory safety and thread safety going back to the C plus example if we were to call the max element function with an empty Vector it would lead to undefined behavior in rust on the other hand the max method returns an option type so if we were to call it on an empty Vector it would simply return the non-variant the option type forces us to check whether the return type is the sum variant or the non-variant which makes our code a lot more robust while preserving blazingly fast performance in other languages like python iterators are not a zero cost abstraction python requires additional runtime checks to ensure the Integrity of the iteration process because collections can change in size or structure during iteration systems programming languages like rust can't afford this type of performance drag next let's talk about one of rust's most fundamental features the ownership model ownership is actually based on the resource acquisition is initialization design pattern in C plus the raii pattern states that resources like allocated memory file handles and database connections should be tied to object lifetimes when an object is created it acquires resources and when the object is destroyed those resources are released here's a c plus example of opening a database connection without using the raii pattern first we Define the DB and DB name variable then we open a database connection check to make sure that DB is not a null pointer perform some database operations and finally close the connection think about what would happen if we didn't close the database connection we would create what's known as a resource leak now I know this is a simple code example but imagine if there there were hundreds of lines of code between the code opening the connection and the code that was supposed to close the connection it's very easy for a developer to forget releasing the resource which is why it happens all the time let's see what this code would look like if we use the raii pattern in this example we've created a class called database Connection in the Constructor we acquired the resource which in this case is a database connection and then in the destructor we release the resource which in this case means closing the database connection then in main we simply create an instance of database connection passing in the database name we then make sure there's a database connection and perform our database operations connection is a stack variable so it will be deallocated at the end of the main function when it's deallocated its Destructor is called and the database connection is closed as you can see this pattern leads to convenient and reliable resource management cleaner and more readable code and eliminates resource leaks in fact this pattern is so useful that rust integrated it directly into the language so you don't have to remember to use the pattern the compiler will simply do it for you by enforcing a set of rules known as the ownership rules the rules are actually really simple the first one is that each value in Rust has a variable that's called its owner there can only be one owner of a value at a given time and when that owner goes out of scope the value is dropped here's how the database example would look like in Rust we have a struct called database connection which holds a connection object when a new database connection instance is created we acquire a database connection and store it inside the struct in Maine we can create a new instance of the database connection struct and pass in our database name and then perform any database operations we want unlike the C plus example there is no Destructor which releases the database connection instead the connection variable will go out of scope at the end of Main and the database connection instance will be dropped and any values database connection is holding will also be dropped this just happens automatically for you like magic but in reality the rust compiler is simply following the ownership rules which as you can see leads to very simple and clean code that avoids resource leaks rust further Builds on top of the ownership Rules by combining them with the borrowing rules the borrowing rules state that at any given time you can either have one mutable reference or any number of immutable references and references must always be valid going back to the rust example you can see that we can create multiple immutable references without any problem but if we introduce one mutable reference we would get a compile time error because we're mixing immutable and mutable references which is against the borrowing rules now you might be thinking why are these rules necessary by enforcing that resources either have multiple readers or a single writer rust prevents an entire class of bugs known as data races and by enforcing that references are valid rust prevents null pointer dereferencing ownership and borrowing are Concepts that many beginners and even intermediates get stuck on or don't have a a full understanding of that's why I always recommend doing exercises or projects focused on these two subjects in the rust developer boot camp which will be released very soon I've created specific exercises and exams for ownership and borrowing but more on that later next let's talk about a couple extremely useful features Russ took from functional languages like Haskell the first one is algebraic data types algebraic data types or adts are a type system concept commonly found in functional languages they allow us to create composite types using some types and product types some types also known as variant types let us Define a type that could be one of several variants for example we can define a shape type which could either be a circle rectangle or triangle product Types on the other hand are similar to structures in C they allow us to bundle multiple types together for example here we have a person type composed of a string an unsigned 32-bit integer and a floating Point number adts are useful because they allow allow us to model complex data structures and enforce constraints on data at the type level which can help catch errors at compile time let's look at how adts are implemented in Haskell here we have an employee data type this is a some type consisting of two variants manager and worker each variant can hold different types and amounts of data a manager has a name and a list of subordinates while a worker has a name and a single manager here's the same example implemented in Rust in Rust adts are implemented through enums and structs enums are some types and structs are product types in this example employee is a subtype so we're using an enum while the concept of adts is similar between rust and Haskell there are some differences rust integrates adts into an imperative programming style unlike Haskell which is purely functional also rust combines adts with other language features like pattern matching lifetimes and the borrow Checker to ensure memory safety and data race prevention I've mentioned powder matching a few times in this video and this is actually another great feature Russ took from functional languages like Haskell in this example we're using the match expression to pattern match on an instance of the employee enum which allows us to handle each variant differently pattern matching in Rust also enforces exhaustiveness which means all variants of an enum must be handled preventing potential runtime errors next let's talk about one of the pillars of object-oriented programming polymorphism polymorphism is the ability of an object or function to take on multiple forms or behave differently based on the context in which it is used some languages Implement polymorphism through inheritance but rust takes a different approach in Rust polymorphism is implemented with traits and generics traits Define a set of functions and methods that types can Implement similar to interfaces in other languages in this example we have a tray called shape with one method called area we can then implement the trait on the rec tangle struct and the circle struct which calculates area differently note that types can Implement multiple traits and traits can have default implementations for functions and methods generics on the other hand enables us to write code that is abstracted over types which leads to reusable and efficient code for example here we have a function called print area which takes the generic argument shape in Rust generics can be bound by traits for example in this case the generic T can be any type that implements the shape trait in main we create an instance of rectangle and pass it to print area we then create an instance of circle and pass it to print area our function can accept both arguments because rectangle and circle implement the shape trait the trait system in Rust has its roots in Haskell's type classes which provide shared behaviors for types but rust Builds on top of the concept of type classes by incorporating ownership borrowing and lifetimes into the trade system which are Central to rust's memory safety guarantees rust also supports Dynamic dispatch with tray objects a trait object that allows you to treat different types that implement the same trait as interchangeable for example here we've created a vector of shape tray objects that stores a rectangle and circle the trade system in Rust has several advantages over classical inheritance it allows for more flexible code design and composition multiple types can independently implement the same trait enabling flexible composition without relying on strict inheritance hierarchies traits are also non-invasive they allow Behavior to be added to types without modifying their original implementation or inheritance hierarchy traits also avoid the fragile Base Class problem where modifications to a base class can unintentionally impact derived classes lastly rust trade system uses static dispatch by default enabling efficient code generation next let's talk about a feature rust stole from JavaScript the async away Syntax for asynchronous program asynchronous programming is a programming Paradigm that allows tasks to run independently and concurrently without blocking the execution of the main program in JavaScript promises provide a way to handle asynchronous operations A promise is an object that wraps the result of an asynchronous operation allowing you to attach callbacks to handle the success or failure of the operation in this example we have a function called get user data which takes a user ID inside the function we use fetch to make an API call because this is an asynchronous operation fetch will return a promise we can call the then method on the promise and pass in a callback which will be called if the operation succeeds and we can call the catch method and pass in another callback which will be called if the operation fails now this code looks pretty readable but imagine if we made the example slightly more complex our function is now called get post data it takes a user ID and a post ID what we want this function to return is the user data the post data and the comments on that post let's imagine that in order to do this we had to make three API calls that were dependent on each other first we have to get the user data then we have to get the post data and finally we have to get the post comments only then do we have all the data we need to return as you can see using promises can lead to deeply nested code which is not very readable let's see what this example would look like using the async await syntax the async away syntax is a language feature that simplifies asynchronous programming by allowing developers to write asynchronous code that looks like synchronous code which makes it a lot more readable the first change we made is added the async keyword before our function definition then inside the function we use the await keyword before every asynchronous call and for error handling we use a try catch block as you can see the code is a lot more readable but there's nothing special going on here in fact async away is syntactic sugar for working with promises rust adopted a similar approach to Acer awareness programming with a slightly different syntax just like with JavaScript the async keyword is added before our function definition inside the function we add dot away to every asynchronous call and we use the question mark operator to propagate errors instead of a try catch block just like with JavaScript the async away syntax in Rust is syntactic sugar for working with Futures which are similar to promises in JavaScript now even though the async away syntax looks similar in JavaScript and rust there are some big differences one difference is that rust's async await model incorporates the zero cost abstractions principle in Rust Futures are designed to be lazy meaning they don't start executing until explicitly pulled by awaiting them this means Futures can be scheduled composed and combined with other Futures without incurring unnecessary overhead Futures are designed this way because of rust's General principle of being explicit which means favoring clear and unambiguous code that requires develop helpers to be explicit about their intentions in contrast promises in JavaScript are eager meaning that they start executing immediately upon creation When A promise is created it initiates the asynchronous operation right away even if the promise is not awaited yet this can result in potentially unnecessary work and resource utilization another difference is that JavaScript is single threaded which means concurrent operations aren't truly happening in parallel instead JavaScript uses a non-blocking event Loop which can handle multiple operations almost at the same time giving the illusion of parallelism rust on the other hand offers true parallelism it can run concurrent operations in parallel by utilizing multiple threads next let's talk about one of Russ's most powerful features macros but before we dive into macros we need to understand meta programming meta programming is a programming technique that allows a program to manipulate or generate code during compile time or run time macros are a language feature that allow developers to Define custom syntax and perform code generation or code transformation they enable meta programming by providing a way to write code that generates or modifies other code during compilation here's an example of a declarative macro in Rust called map which is used for creating hash Maps declarative macros are defined using the macro rules keyword these macros take code AS input match it against a set of patterns and generate new code based on those patterns at compile time the first pattern matches when the macro is invoked with two type Expressions separated by a comma as arguments if the code pass then matches this pattern the macro will generate code that creates an empty hash map with the specified key and value types the second pattern matches when the macro is invoked with a comma separated list of key value pairs separated by an arrow the asterisk symbol denotes repetition allowing multiple key value pairs to be matched this pattern is used to create a new hash map and populate it with the specified key value pairs here's an example of how this macro can be used instead of creating a hash map manually we can call the map macro and pass in the types for key and value Pairs and instead of calling the insert method to populate a hash map we can simply call the map macro and use the arrow syntax with just a few lines of code we've been able to extend the rust language with some new syntax one cool thing about rust macros is that they're hygienic which is a feature rust took from scheme hygienic macros is a concept that ensures the variables and identifiers used within a macro do not accidentally clash with the variables from the surrounding code in this example we have a greet macro the macro has one pattern which matches against any expression and expands into code that prints a greeting using the provided name notice that the macro captures the provided name in a local variable in the main function we Define a name variable and then invoke the Greek macro passing in the name variable this example demonstrates the hygienic nature of macros in Rust the variable name used within the macro doesn't clash with a variable name in the surrounding code thanks to the automatic renaming and scoping mechanisms of the macro system even if we change the value of the name variable inside the macro it will not affect the surrounding code if we run the program you can see that John is printed which is the value of the name variable inside of main lastly let's talk about a feature rust stole from the world's most popular web framework before we get to that keep in mind that gaining a deep understanding of these incredible rust features and how to use them in real world applications takes a lot of practice that's why I created the rust developer bootcamp which I'll talk more about at the end of the video in 2009 Ryan doll revolutionized JavaScript by introducing node.js a JavaScript runtime that allowed JavaScript to break beyond the confines of the browser this led to an explosion of javascript-based back-end applications alongside node.js Ryan also created node package manager or npm for short giving developers a powerful tool to manage dependencies and share code within the node.js ecosystem shortly afterwards mpmjs.com was created serving as the central hub for hosting and discovering public packages Russ took this idea and ran with it by creating cargo and crates.io cargo is rust's official build system and package manager it handles many tasks such as building code downloading and compiling libraries and managing rust versions and configurations these operations can be performed with simple CLI commands like cargo build cargo test and cargo run similar to npm commands like npm install npm test and npm start in node.js applications dependencies are listed in a file called package.json similarly in Rust dependencies are listed in a file called cargo.tomel in node public dependencies are pulled from mpmjs.com and in Rust public dependencies are pulled from crates.io cargo and crates.io enable reliable dependency management streamline project building integrated testing and simple package distribution which are features the systems programming space has lacked this makes development so much easier that it might be my favorite rust feature all these features make Russ the incredible language that it is but understanding how each feature works together and how to use them in practice can be very difficult that's why I created the rust developer bootcamp you guys have been emailing me and asking me to create a high quality comprehensive rust learning program that goes far beyond my YouTube videos and that's exactly what I've been working on for the past year the Russ developer bootcamp is the all-in-one rust learning program I wish I had when I was first learning rust I've included over a hundred videos covering anything you ever want to know about rust I've also included coding exercises exams and real world projects to help you internalize the lessons now the rust developer bootcamp is launching very soon so to get Early Access head over to let's get rusty.com bootcamp with that said I hope you enjoyed the video and I'll see you in the next one
Info
Channel: Let's Get Rusty
Views: 291,094
Rating: undefined out of 5
Keywords: rust programming language, rust programming tutorial, best programming language, rust programming, programming language, programming languages, programming in rust, rust coding tutorial, how to program with rust, rust tutorial introduction to rust programming, rust coding, rust language, rust-lang, rust lang, rustlang, learning rust, writing rust code, RustCommunity, RustLearningResources, RustFeatures, RustFeatures2023, rustdeveloperbootcamp2023, rustdeveloper
Id: 784JWR4oxOI
Channel Id: undefined
Length: 21min 30sec (1290 seconds)
Published: Sat Jun 17 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.