My Experience with Rust as a Java Dev

preview_player
Показать описание

I like Rust better than Java. I'm making this video to better understand these concepts by trying to explain them to you... or at least my understanding of them. That's how I learn best. If I'm misunderstanding something, let me know. This is just the beginning of my Rust journey.

0:00 i'm learning rust
0:30 ownership... where are my objects??
1:55 rust compiler is beautiful
2:45 no garbage collector??
4:04 borrowing
6:14 borrow checker
7:58 traits
9:32 null doesn't exist?? (Option)
11:35 variables are immutable... nice
12:18 cargo
13:25 GLAZING RUST
14:25 rust gave me an epiphany
17:03 i'm still learning rust... any advice?
18:15 vec![] or Vec::new() ??

Don't know why you'd want to follow me on other socials. I don't even post. But here you go.
Рекомендации по теме
Комментарии
Автор

I think there's a misunderstanding here regarding traits in Rust. Traits are both Generics and Interfaces, and the way they work differs from Java.

In Rust, impl YourTrait or <T: YourTrait> are compile-time interfaces. When you use these, Rust generates specific code for each type that implements the trait. This process is called monomorphization and ensures zero-cost abstraction, meaning no additional runtime overhead.

Monomorphization allows you to define a contract for your inputs (through traits) and still have efficient, specialized code for each type at compile time. This is why Rust can offer powerful abstractions with no runtime cost.

In contrast, &dyn YourTrait in Rust is for runtime polymorphism and is similar to Java interfaces. When you use &dyn YourTrait, you are creating a trait object that allows for dynamic dispatch at runtime. This is essentially equivalent to Java's interface system, where you can pass around different concrete types that implement the interface, and the method to call is determined at runtime.

In Java, interfaces are purely runtime constructs. If you want to handle types that are Comparable, you would use the Comparable interface. However, in Java, you can't specify that a particular class must implement a method (like compareTo) without having to go through vtable checks at runtime.

While Rust doesn’t strictly follow the Object-Oriented Programming (OOP) paradigm in the traditional sense, it still supports message passing and polymorphism through traits. This approach is what OOP originally focused on — defining behavior through interfaces or contracts — and Rust does it with zero runtime cost for compile-time traits and with dynamic dispatch for runtime traits.

I’d recommend reading the Rust Book section on monomorphization and polymorphism. I believe you’ll find that Rust’s trait system aligns closely with OOP principles, but with much more efficient abstractions.

MePatrick
Автор

1:42 why don't you have rust-analyser enabled? You can get those errors live as you type.
4:00 in rust, when you finish drinking, your mug is automatically de-allocated ;)
9:00 traits allow you to write higher level logic, without assuming a backing type. For example, writing a function that does something to every element of a vector, versus any object that implements iterate, in the latter case you can use it also for arrays, hashmap values, whatever.
13:00 this bit is probably it just being a newer language, there's a lot of benefits of hindsight when it comes to things that turned out to be inconvenient about older build tools.
16:00 I don't like this way of putting it "rust forces you to do X", again, with the benefit of hindsight you've hopefully already realized that doing X is a good policy when writing code and saves you headaches in the longrun, rust just automates the process of checking that X is done, which is what you were going for all along anyway, e.g. trying to not have other pointers when you have one mut one (it's easy to miss one out, hard to scour your codebase to see where you slipped up, good to be able to be sure it hasn't happened).

johanngambolputty
Автор

Two devs walk into a restroom and take a piss. Java dev proceeds to sink, Rust dev proceeds to the door:


JavaDev: “In Java, they teach us to wash our hands after we pee.”

RustDev: “In Rust, they teach us not to piss on our own hands.”

layerdown
Автор

I"m loving Rust for long-running processes I've been writing to migrate data between different Salesforce Orgs as it just runs for days if it needs to. Killing all the bugs at compile time is very helpful in that respect.

EdElliott
Автор

Traits are awesome. I think of the language as a buffet since you mostly opt in to behaviors / patterns vis composition, and you get to assemble your plate with whatever you want (traits, generics, impl struct), but the chefs that offer the food use their combined experience and knowledge to prevent you from choosing a bad combination of food items (borrow checker + compiler).

eaglethebot
Автор

It's nice hearing your experience.
Nitpick at 1:51 *Level* didn't "get cleaned up". The distinction matters in C++ where the moved-from value keeps existing and must be left in a sane state. For instance by implementing move on Vec so that the moved from vec is cleared to avoid a double-free of the data on destruction.
With the Rust ownership model, the compiler ensures the old value doesn't "exist" anymore so it doesn't have to be cleaned up and we can forget about it. It's simpler and cheaper.

AlexandreJasmin
Автор

As someone fairly new to programming, Rust is a hard but excellent experience. The Rust Programming Language book is amazing so far, the compiler screaming at you all the time but giving you precise info what went wrong and how to fix it and Cargo giving you docs for dependencies that you can run in your browser using cargo doc --open is like a dream developer experience. Coming from javascript hell, I fell in love with rust and it's ecosystem. It being a low-level language teaches you a lot about how computers work and that is also amazing

jmecinski
Автор

Personal anecdote - I had a lot easier time learning Rust for the second time by spending a few weeks with Elixir, beforehand, to better grasp functional programming concepts and shift my OOP-only mindset.

misck
Автор

I'm really feeling like I'm following very closely in your footsteps. I'm primarily a Java developer (hit my 5 year professional mark in October), and I'm really wanting to learn Rust. On top of that, I've switched to Neovim as my editor this year. I'm glad I'm not the only one to make comparisons between life and programming lmao. Good luck on your Rust journey!

xMaticusfinchx
Автор

About Vec::new() vs vec![], if you look at how the vec![] macro works, under the hood it calls Vec::new() if you dont provide any parameters, so you can use either one, personally I use Vec::new() though because I think it has better readability 😁

realtitedog
Автор

5:42 you say when levels is mutable only one & is valid, this is not the case, you can still have as many of those immutable references (&T) as you like OR you can have ONE SINGLE mutable reference (&mut T), think about it in terms of data races. I can have multiple READ ONLY references without any issues, but I can't have thatnwhen there is a READ/WRITE reference in the mix, same reason as to why only 1 &mut T is allowed, not multiple (T is just a placeholder for a type here)

sstijn
Автор

welcome to the cult of the crab, we like it here

havocthehobbit
Автор

Cargo is excellent. Made managing projects dependencies easier.

analisamelojete
Автор

The analogy about Rust being a "grown up" language makes total sense. Total sense - right there with you.

JeffPittman
Автор

As Java dev I found Rust to be surprisingly similar to Java in code readibility. Way more than for example Go. For business logic-heavy software I would stay with JVM languages but I really like Rust for tinkering with microcontrollers and would be okay with using it if I have to write extremely performant software.

RuskiRozpierdalacz
Автор

11:50 The "allow less by default" is something I like.
I just realized that's similar to using programming langugaes with libraries. By default you have no libraries, but if you import enough libraries, you basically have something that's close to an engine.
And engines allow you a lot by default, and you have to disable things you don't want manually if that's even possible, just like you have to disable mutablilty in Java.

porky
Автор

Forrest, this is amazing. As a major Java developer at work, and at home, I've dabbled in a lot of different languages. But nothing has prepared me for this "ownership" and "trait" system like Rust has. Go comes *close*, but only to some degrees. I really appreciate that you took the time to explain all this to help yourself learn, since that's the way I learn as well. Lastly, I love the coffee cup analogy, since that's exactly how life works in my house.

ibonny
Автор

Based on your experience and since you asked, my advice is: don’t be afraid to name lifetimes and generic types other than ‘a or T or whatever. Lifetimes and generics will propagate throughout your type tree and knowing what specific lifetime they are referring to or generic type you are referring to is really helpful for understanding or connecting things together. The type system is basically its own language and to make the intent readable for yourself or someone else later, name things in this space accordingly. T or ‘a is being lazy unless it’s really simple. Rust is a great programming language and once you see what I am talking about here in some more complex situations you’ll realize, which is my second tip: before you start a Rust project: do I really need to make this perfect zero abstraction tool or can I let go and do it good enough with something else?

bpo
Автор

Some advice when coming from heavy oop languages to Rust: learn to properly devide data from functionality!
In oop wie learn that data should also do things (looking at you shape-drawing example!). But in rust you should have types for data (which maybe have conversion functions) and types with real functionality!
E.g.: String is data. You have some functions to create and concert from and to strings. But you shouldnt have a function which write to a file attached to the string! Writing somewhere is functionality. So you will have some types like File and TcpStream which have the functionality to write to a file in the filesystem or to via a tcp-socket.

Having this mental model of data vs functionality makes writing code much easier! But it should not be a hard rule in the long run!
E.g.: you want to write to memory instead into a file. Thats why Vec (data) implements the Write-trait (functionality). Having an extra VecWriter would be overkill hence mixing data and functionality in *some* cases might be ok.

PsyKai
Автор

3:24
> preventing the mess in the first place
Very good point. These restictions force me to structure my code better.

For example when doing a graph, I don't have a bunch of nodes on the heap, who reference each other.
This can lead to memory fragmentation and if I want to move a node around in memory, this will be pretty difficult.

Instead I use a simpler concept and represent it as a list of objects, which are all in a continuous list, improving cache locality. They might have data connected somewhere else, but also not more than the garbage collected node.
I might also just represent them as sparse matrices, which already have good and efficient implementations.

porky
welcome to shbcf.ru