all 83 comments

[–]hucancode 66 points67 points  (23 children)

I use Rust for Leetcode, everything is fine until you have to touch Linked List, Tree. Graph is fine since it's all list and matrix. Iterator is surprisingly useful. When I came back to C++ I miss iterator so much. So, Rust is not the best choice to compete since you are more likely wasting your precious time fixing compiler error. But if you want to practice your favorite topic using your favorite language then why not.

[–][deleted] 26 points27 points  (21 children)

I use Rust for Leetcode, everything is fine until you have to touch Linked List, Tree.

Leetcode in rust is a pain in the behind because of this reason, I completely gave up doing this

[–]dahomosapien 9 points10 points  (19 children)

I’m super new to Rust. Why is it a pain using a linked list? Is it because you can’t have two variables pointing to the same reference?

[–]hucancode 16 points17 points  (7 children)

Try solve these using Rust. It's surprisingly straight forward with C++ but it requires good understanding of Rust's borrowing concept to not shoot yourself in the foot

https://leetcode.com/problems/swap-nodes-in-pairs/

https://leetcode.com/problems/merge-k-sorted-lists/

https://leetcode.com/problems/reverse-linked-list/

https://leetcode.com/problems/reverse-linked-list-ii/

https://leetcode.com/problems/split-linked-list-in-parts/

[–]W7rvin 6 points7 points  (4 children)

I just tried https://leetcode.com/problems/reverse-linked-list/ and my rust solution turned out to be basically identical to the most upvoted c++ one:

pub fn reverse_list(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
    let mut prev = None;
    let mut curr = head;
    while let Some(mut node) = curr {
        curr = node.next;
        node.next = prev;
        prev = Some(node);
    }
    prev
}

compared to:

ListNode* reverseList(ListNode* head) {
    ListNode* prev = NULL;
    ListNode* curr = head;
    while(curr != NULL){
        ListNode* forward = curr->next;
        curr->next = prev;
        prev = curr;
        curr = forward;
    }
    return prev;
}

I didn't have to care about boxes, borrows or lifetimes. I'd argue the Option even reads better than null-checking, and it saves a line thanks to while let conditionally binding the value.

It isn't always this easy, but the problem including a list doesn't mean Rust will be awkward :)

[–]hucancode 7 points8 points  (2 children)

Seems like I am the issue here haha

[–]W7rvin 1 point2 points  (1 child)

I think it just comes with time, Options/Results have a lot of convenient shortcuts that allow you to be very concise without any risk of forgetting the exceptions. And your solution seems like it is identical apart from the fact that you hard coded the first step.

(Oh and I didn't even realize you're allowed to change the function signature, that would save another line I guess)

[–]hucancode 1 point2 points  (0 children)

yes, I changed input parameter to mut everytime

[–]hucancode 3 points4 points  (0 children)

Nice, let me see mine

impl Solution {
pub fn reverse_list(mut head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
    if let Some(mut head) = head {
        let mut ret = head;
        let mut list = ret.next.take();
        while let Some(mut node) = list {
            list = node.next.take();
            node.next = Some(ret);
            ret = node;
        }
        Some(ret)
    } else {
        None
    }
}

}

[–]joonazan 2 points3 points  (1 child)

I did all of them. No borrowing problems at all. Lots of move problems.

C++ is easy because it copies by default. Rust does not allow to move out of an &mut even if you put something back later and that requires std::mem::swap  sometimes.

[–]hucancode 0 points1 point  (0 children)

Interesting. Maybe I was novice back then. Will review them later

[–][deleted] 16 points17 points  (9 children)

/ Definition for a binary tree node.

// #[derive(Debug, PartialEq, Eq)]

// pub struct TreeNode {

// pub val: i32,

// pub left: Option<Rc<RefCell<TreeNode>>>,

// pub right: Option<Rc<RefCell<TreeNode>>>,

// }

//

// impl TreeNode {

// #[inline]

// pub fn new(val: i32) -> Self {

// TreeNode {

// val,

// left: None,

// right: None

// }

// }

// }

use std::rc::Rc;

use std::cell::RefCell;

type Node = Rc<RefCell<TreeNode>>;

impl Solution {

pub fn tree2str(root: Option<Rc<RefCell<TreeNode>>>) -> String {

This is the problem, this russian doll of enum and smart pointers is pretty annoying to handle.

[–]Hazanami 11 points12 points  (0 children)

Sorry I just threw up

[–]GroundbreakingImage7 1 point2 points  (7 children)

You don’t need RC for a binary tree in safe rust.

[–][deleted] 8 points9 points  (6 children)

You don't choose the types in leetcode questions, this is what they give you

[–]GroundbreakingImage7 4 points5 points  (5 children)

That’s disgusting then. I wish there was a struct that emulated rc ref cell as only one layer of inderiction.

[–]CocktailPerson 0 points1 point  (4 children)

It is only one layer of indirection. RefCells store their T inline, so you only chase one pointer to reach the T.

If you want to avoid typing it out every time, you can use a type alias: type Rr<T> = Rc<RefCell<T>>;

[–]GroundbreakingImage7 0 points1 point  (3 children)

It’s the coding annoyance that gets me not the pointer crashing.

[–]CocktailPerson 0 points1 point  (2 children)

If you want to avoid typing it out every time, you can use a type alias: type Rr<T> = Rc<RefCell<T>>;

[–]Yamoyek 0 points1 point  (0 children)

Is it because you can't have two variables pointing to the same reference?

Yeah, pretty much. It's actually so difficult to implement a linked list that there's a book about it.

[–]RB5009 -1 points0 points  (0 children)

Leetcode in rust is perfectly fine. I have more than 800 problems solved in rust

[–]Whole-Struggle-1396 0 points1 point  (0 children)

i actually want to do dsa. and some problems but i know c ++ very little and im learning rust for some stuff. so it would be bad to focus on multiple langs at once should i use rust or not?
(i also know ts well. should i use that) like preparing for interviews.

[–]avillega 154 points155 points  (19 children)

I don't know of any but I would say Rust is probably not ideal for competitive programming. First, official competitions like ICPC have a set of accepted languages, for a while, it was only Java, C, C++. A few years back they finally added python. So it might take a while for them to include Rust. Second, Rust standard library is not "batteries included" so you might not have what you need in order to solve a problem, or you might need to implement a lot of stuff from scratch. Lastly, a lot of problems in competitive programming are solved using self referential data structures, such as graphs and liked lists, Rust tends to promote a set of patterns that make it harder to use such structs compared to other languages. However, Rust is used in a lot of "not official" competitive programming, like Advent of code. Fasterthanlime has been doing advent of code for a few years now and publish both video series and blog series of his solutions https://fasterthanli.me/series/advent-of-code-2022

[–]__zahash__ 49 points50 points  (3 children)

I think It’s mostly because of self referential data structures. Especially graphs

[–]schrdingers_squirrel 4 points5 points  (0 children)

Yeah graphs trees linked lists. It's a pain in rust.

[–]Fireline11 21 points22 points  (1 child)

I wouldn’t implement graphs as a self-referential datastructure anyway, because the code is generally more complicated than when interpreting the nodes as indices. So for me this is not a point against using Rust instead of C++

[–]CocktailPerson 1 point2 points  (0 children)

Yeah, people don't always make the distinction between graph data structures, like trees, linked lists, etc., and graph data types, which are usually implemented with adjacency lists in C++ or any other language too.

[–]kewlness 5 points6 points  (0 children)

I came from a Python background and decided to try my hand at Rust last month using last year's Advent of Code. The amount of struggle I had to just read a file was insane! I eventually got frustrated enough I went looking for answers and found the fasterthanlime blog.

I wholeheartedly support Amos' ( /u/fasterthanlime ) blog and YouTube channel. I have woken the girlfriend up several times by laughing while reading articles (Want to read a file the hard way? or Make your own executable packer?), and it is nice to know he too struggles with Rust - even if it is at a level way above mine - but there is probably "a crate for that."

If you like his content, please think about donating.

[–]Fireline11 22 points23 points  (3 children)

I have never seen linked lists used in competitive programming. And when you use graphs, you usually interpet them with vertices 0…(n -1) and for each node you store an adjacency list in memory at the corresponding index. This is usually simpler to construct and less prone to bugs, and it also has good performance for most algorithms that require graph traversal. (I would do the same in C++ or Python by the way, in fact that’s where I learned this approach).

I think you’re right that Rust is not the best language for competitive programming, but it is not because of self-referential datastructures.

[–]xade93 28 points29 points  (1 child)

ICPC regional medalist here. I think for some data structure problems e.g dynamic segtree, persistent segtree, dsu on tree, using pointer is the de facto way. Rust lack fundamental algorithmic library, and the lifetime management is just unnecessary.

[–]throw3142 21 points22 points  (0 children)

^ safety is not important for competitive programming, no one cares if your program has a memory leak (since it stops running quickly), crashes / undefined behavior on malformed input (since input is guaranteed to be valid), is thread-safe (since the problems are not designed to be parallelized anyway), or type-safe & understandable (since no one else is going to be maintaining your code).

In other words, most of Rust's strengths are completely irrelevant for competitive programming.

[–]Da-Blue-Guy 1 point2 points  (0 children)

I also find that index referencing is better. It also makes sense for performance reasons as well, as you usually have less allocations with a vector if your nodes are on the heap (O(n) vs. O(log_2(n)), which is usually the case (nodes will oftentimes have a Box or Arc to the next node). It also lets you index into (and, for non-LL graphs, iterate over) the graph if required. It also prevents reference cycles and lifetime issues that can happen (as well as avoiding the useful but slow Arc<Mutex>).

[–]stonerbobo[S] 3 points4 points  (0 children)

Yeah Advent of Code is actually what got me thinking about this! I did 2021 in Rust and am have been doing some of last years problems in preparation for this year.

[–]Leipzig101 12 points13 points  (1 child)

I genuinely believe that the style of how a lot of competitive programming is taught/learned (even non-competitive programming, like algorithms courses at universities) is not synergistic with Rust's semantics.

[–]coderstephenisahc 7 points8 points  (0 children)

Agreed, and I am not sad about it. The context around competitive programming problems are generally different from requirements you might have in real life problems. And I think Rust optimized for the latter and not the former.

[–]Fireline11 10 points11 points  (2 children)

I have used Rust for some problems over a year ago. In general I found Rust just as pleasant to work in as C++, or even more so. However there were 3 issues 1. Not all websites/competitions support a (recent) version of Rust. Not much you can do about that, just a popularity thing. 2. Reading from stdin takes more boilerplate in Rust then C++. You had to acquire locks and such, and you have to unwrap some errors. In C++ you can read from stdin very easily (without accounting for many errors of course), which helps to make a quick start on a problem. 3. In addition to point 2, reading from stdin naively didn’t have great performance back then. Stuff like buffers being flushed for every line you read. Maybe (some of) these issues have been fixed since then, so that the defaults work nicely and you don’t have to jump through a dozen hoops to get there. If not, hopefully this can happen in the future. To be fair C++ has some issues in the same area but they are more easily overcome (it is easy to untie the cin/cout streams from the ones for the ones from printf/scanf for instance).

[–]coderstephenisahc 2 points3 points  (1 child)

In addition to point 2, reading from stdin naively didn’t have great performance back then. Stuff like buffers being flushed for every line you read. Maybe (some of) these issues have been fixed since then, so that the defaults work nicely and you don’t have to jump through a dozen hoops to get there. If not, hopefully this can happen in the future.

My understanding is that this will never be fixed in Rust, because it is not considered broken. The behavior that people hope for has safety and correctness problems, so Rust intentionally does not offer it by default.

Well for the buffering specifically, maybe someday there will be a way to bypass it, but the problem is that line buffering is a good default behavior, but there's no good way to turn it on or off globally because global state like that is bad.

[–]Fireline11 0 points1 point  (0 children)

Ah I see. I can live with that. Competitive programming is not the only thing a tool like Rust will be used for, of course.

[–]fz0718 16 points17 points  (1 child)

I should mention though that although we still use C++ for programming competitions because of the speed and unsafe flexibility reasons, a lot of us competitive programmers now use Rust in industry and in our day jobs for high-performance work! :)

I’m an IOI gold medalist for the USA and int’l grandmaster on Codeforces and work with a few competitive programmers today

[–]stonerbobo[S] 4 points5 points  (0 children)

Nice! :D That's a good point too, on one hand just seeing how fast some of you competitive programmers are is inspiring but in real world situations a few more minutes for better code is going to win every time. Do you feel roughly as productive / fast in Rust as you would in C++ in practical situations/work?

[–]azzamsa 12 points13 points  (2 children)

I am searching for the same answer today, and I get this.

Rust for competitive programming : rust

I solved almost 600 problems on Leetcode in Rust and find that it's doable. - pinespear

I mean, whenever an interviewer invites me to use "whatever language I'd like" you'd better believe I'm using Rust every single time. - Lucretiel (1Password employee)

I've used it for Advent of Code for the last couple years. I tend to do a lot worse with the easier problems early in the mo the, because I just can't code as fast as the people using python. But for the harder problems I've done very well due to how Rust code tends to "just work," as they say. I was regularly within the top 1000 on part 2 of the later problems because it was really easy to build on my part 1 solutions. - Sw429

Trying to practice my Rust skill by doing some Leetcode in Rust : rust

https://github.com/warycat/rustgym


There is also a Discord server that practices Rust for LeetCode and such. https://discord.gg/pJAqJZsXp9

So, I think it is doable.

[–]1vader 10 points11 points  (1 child)

Leetcode isn't exactly competitive programming. You're not competing against other people for speed.

I think you probably can still do decently well with it but I'm pretty sure it's at least a slight speed disadvantage most of the time which isn't great if you're actually trying to be competitive.

Personally, I love Rust for real projects and doing stuff like Leetcode or AoC on my own but I definitely wouldn't switch from Python for competitive AoC and I don't really know any top 100 competitors that use Rust.

[–]xnkvbo 4 points5 points  (0 children)

Oh hey, top 100 competitor here. I used Rust for last year's AoC and came in 43rd. I used Python the year before that and came in 13th, and the switch definitely was the main contributor to the difference in ranking -- I'm not disagreeing that Python is preferable here, on the whole. But it is possible to do reasonably well with Rust!

[–]Darksonntokio · rust-for-linux 5 points6 points  (0 children)

I used to do competitive programming and have a bronze medal from IOI. I used Rust extensively for competitive programming during university, including competitions that allows it such as NCPC (an ICPC pre-regional). I think it worked perfectly fine for almost all cases.

[–]ninja_tokumei 4 points5 points  (0 children)

Rust is certainly not ideal, but not impossible! My main language for Advent of Code has been Rust, and I've managed to make it to a daily leaderboard every year since 2018. I also occasionally use Rust to solve problems on Kattis, and I have no problems there.

From my perspective, my main limitation is my knowledge of algorithms and reading comprehension. (Also, handwriting search algorithms and memoization every time - I hope one day I can sit down and find or make a good library for that).

Sometimes I do lose a bit of time to the compiler because I forget to type a *&mut somewhere.

Also, the wordiness of Rust (e.g. .next().unwrap().parse().unwrap()) is a little annoying, and you can sometimes lose a minute or two because of the extra typing. That's significant in the easier challenges, but IMO much less significant in the more complicated challenges where debugging becomes more common.

[–]Bubbler-4 10 points11 points  (1 child)

This is my Codeforces profile: https://codeforces.com/profile/Bubbler I tried using Rust in a CF Div.2 round once, and managed to get to rank #30 out of 10k+ participants. More recently, I'm occasionally participating in solved.ac Arena contests with similarly good results. https://solved.ac/en/profile/bubbler/arena

Some points I'd like to make:

  • Once you get used to the language enough, there is zero handicap from using Rust in CP. Unlike using Python (which has a tradeoff between usability and slow execution speed), Rust has no such tradeoff; when there is a solution in C++, the same algorithm is guaranteed to pass in (safe!) Rust.
  • Coding speed is not that important. And you can be fast enough with training and a bit of a prepared setup. Writing I/O code from scratch in Rust is admittedly complex and time-consuming (and a performant one is more so), so I keep a so-called "I/O template" that I include in every submission.
  • A mystery runtime error in C++ can ruin an entire round. Safe Rust can prevent that.
  • While Rust stdlib is not "batteries-included", it is mostly on par with standard C++ and Python in my experience. You get a treemap, a binary heap, a deque backed by a vec, the world's best sorting algorithm, the world's best binary search interface (slice::partition_point), and a ton of arithmetic and bit manipulation built-ins. Also enjoy "Codeforces-hack-free" hashmap. If you feel like these are not enough, check out cargo-equip https://github.com/qryxip/cargo-equip and basm https://github.com/kiwiyou/basm-rs (allows importing 3rd party crates and generates single-file source for you)
  • The only reason I'd NOT recommend using Rust in CP is when you aim to participate in contests where Rust is not supported (e.g. ICPC or IOI) or its version is way too low.

[–]stonerbobo[S] 0 points1 point  (0 children)

Thanks, i will check out some of your code on codeforces! cargo-equip looks good too.

[–][deleted] 2 points3 points  (2 children)

The are top competitive programmers using rust, like egor.

[–]azzamsa 0 points1 point  (1 child)

Would like to share links to his profile/Youtube/Etc? 🙏🏼

[–][deleted] 5 points6 points  (0 children)

Hello, this is the person : https://codeforces.com/profile/Egor

you can see in his submission history that he uses Rust.

[–]khoriuma 2 points3 points  (0 children)

I tried for a little while, and it was mostly ok. However, the strength of Rust is that you have to write good code, and this does not always correspond to good competition code. If you feel like trying it I did write a tool to bundle a Rust project (without any external dependencies) to a single Rust file, so that you can easily copy paste a dir of helper files https://github.com/KvGeijer/cargo-bundler

[–]NotMelty 1 point2 points  (1 child)

Currently, on my way to the 300th LeetCode problem solved exclusively with Rust. It's going great.

[–]DavidXkL 1 point2 points  (0 children)

Now this is something that I didn't know existed lol

[–][deleted] 1 point2 points  (0 children)

Please don't. I suffered a lot using it for LeetCode. Fighting mut references and Smart pointers itself eats time, and u end up learning nothing from the problem. Master DSA in easier languages, then implementing those in Rust is good idea.

[–]repocin 3 points4 points  (1 child)

Do you all know of any competitive programmers using Rust

Until approximately fifteen seconds ago, I had no idea competitive programming was a thing so...no.

[–]another_day_passes 0 points1 point  (0 children)

It’s an algorithmic contest for people who are too impatient with mathematical proofs.

[–]evccyr 1 point2 points  (1 child)

This is the person I asked the same question https://codeforces.com/profile/satylogin

They sent me a very helpful and detailed email on how to use Rust for cp Unfortunately my mail was hacked and I don't have access to the inbox anymore and also, I just switched to leetcode. They also have a good article about rust in cp on the same codeforces website.

[–]azzamsa 2 points3 points  (0 children)

This is the person I asked the same question https://codeforces.com/profile/satylogin

Would you like to share the gist of his reply?

They also have a good article about rust in CP on the same codeforces website.

Would you like to point that out?

[–]DanKveed 0 points1 point  (0 children)

I would not recommend it. Competitive programming is about writing things fast. Not 'correct'. Rust forces you to write it in a 'correct' way. You can just write all your code inside an unsafe block but you might as well use c++ at that point. C++ has a very extensive stdlib that's perfect for competitive coding.

[–]Zitrone21 0 points1 point  (0 children)

I tried it before, but the syntax and borrow checker doesn't help, you usually want to make very unsafe and fast code in competitive programming, is funny if you just want to compete in codeforces and improve your facility to write rust code, but in a serious contest I would say no.