Open source projects with high quality code

I was listening to this discussion with Matklad, and he argues that when the level of competence is not very high, a codebase drifts into “default Rust” - heavy use of Arc/Mutex, RefCell, etc..

For educational purposes I’m looking for open-source Rust projects that have high quality of code and use the language in a more concise or simpler way (if that's the right word to use here).

Thank you so much in advance.

EDIT: I can't thank you enough for the useful tips and hints. Thanks a lot!

3 Likes

Just for clarification, there's nothing inherently wrong with using Arc, Rc, Mutex, RefCell, etc.; as with any other tool: Sometimes they are the right tool for the job... and sometimes they are not.

You might be suffering of a form of anxiety called FOMO... but this is the wrong way to go about it. You'll never learn when it makes sense to use i.e. a Mutex and when it does not if you never use it!

That is, you cannot avoid the empirical part of the learning process, no matter what these sensationalist YouTubers might imply otherwise.

20 Likes

Thanks a lot for your reply.
Yes in general you are right, but from my point of view it is just an example of complexity.

PS
Yes it is unfortunate that those youtubers were involved in this discussion, but Matklad is a very well known person in the Rust community. He created or was the main contributor of the rust_analyzer.

1 Like

I know who Matklad is :). He has my utmost respect.

2 Likes

I read the std for learning

9 Likes

Don't believe everything you you read on the internet. When you push an agenda of something being better you come out with such statements. I personally go with pushing the use of iterator over code using index.

The heavily used term in rust is idomatic code. See the forums search. I would say instead to focus on code that has documentation and tests if you want to see high quality.

5 Likes

At the end of the day, all these "clean code", "bad code", "idiomatic use", "concise code", "high quality code" etc. are plain personal taste. There are no objective criteria to them.

I don't say there are no precious thoughts and insights in those discussions. Indeed there are a lot. But they are not the final answers.

Types like Arc, Mutex etc. are not complex. Quite the opposite: they have well-defined purposes, small impacts and, in the case of Rust, expressive and safe interfaces.

Of course, complex systems can be built with these types. But this also applies to any other type. These types are not the cause of complexity.

Today, multi-core CPUs are everywhere. If you want to take advantage of the power of these CPUs, you have to use some synchronization primitives.

2 Likes

I don't think that's actually true. Sure, there there might be multiple reasonable local optima, but there's lots of things that are unambiguously worse. See this old post for example :upside_down_face:

And some things we now know are just better, like including the , on every element of a line-wrapped list.

Some things sure are down to taste -- like if it's [ 1, 2 ] or [1, 2] on a single line -- but there are absolutely objective criteria for some things.

5 Likes

Taking the standard library as reference is a good start.
Most widely used crates also have a high-quality code base, especially when there are numerous competent contributors.
After having read this thread I strolled through my repositories and looked for presentable examples. While doing so, I noticed some potential improvements in some of my crates, especially the older ones. This can be a sign that one has improved as a programmer.
I found one example where I could not find too many things "wrong" with it:

Is it high-quality code? You be the judge!

1 Like

I would suggest wasmi - Rust, will teach you a little about memory management.

1 Like

I really can't point at any crate, usually it went like this:

  • I am using some crate
  • I want some feature
  • I contribute
  • During writing the code I understand some part of the code base and find new cool tricks or patterns and use them in my new code too

Or

  • I am using some crate
  • I am not 100% sure how would've I implemented it, there is some ambiguity in my mental model
  • I inspect the code
  • Learn

So, I think it won't hurt to just read code for every dependency you are directly using - so that you understand the use case and know what to look for, think of implementing it yourself and adjust the mental model. Rinse and repeat.

7 Likes

You could search curated list of crates for good examples. There were several of those lists, like

Some of those are not the most recent, unfortunately.

Look for mature crates: if possible, major version >= 1 (not in beta any more), widely used and actively worked on, with signs of frequent refactoring and maintenance.

For educational purposes—I don't know if you mean for you or as a teacher—I would recommend working by theme first, though. Those random projects and crates are large and mix very different levels of difficulty (and language eras). They're also very focused on one problem: multithreading, procedural macro, base library components, ...

There's a series of very good websites made by some of the people around and some great books (try Effective Rust by Drysdale) offering a more thematic and structured approach.

1 Like

You need to look in many projects, because just one will give you a cut of only certain features of Rust. I simply take a look in source repositories of crates I use from crates.io, and it covers my curiosity of a quality code. And at the end, I ask here to review my code.

1 Like

What "high quality code" means?

Code have many sides and it is hard to make every side high quality code.

For example:

  1. Documentation
  2. Naming
  3. Code seperation into modules
  4. Tests
  5. And so on...

Here are many crates which will have high quality code seperation, but non-existent documentation. Is this high quality code or not?
Other code may have high quality documentation, but no tests. Is this high quality code?

What type of error handling would you call "high quality code"?
Is this "high quality code"?
return Err("Some error message");

Should here be one error enum in crate or should every function have its own errors?
Not long ago I have read this Modular Errors in Rust
and I like idea. So, now I think crate using this modular errors is "high quality code", at last in error handling. But how about documantation? How about Naming?

While code can be "high quality code" from one side of personal option, it may be "low quality code" from other side. And this also will be just biast option of person.

Like discusion in C and C++. How shoul pointer be writen.
int* var_name;
int * var_name;
int *var_name;

This is all just personal bias.

2 Likes

Which parts of std? Sometimes I'll look up the source of a method on, say, Vec, and it's all kinds of unsafe pointer manipulation with incredible care given to only Dropping items once that I wouldn't consider standard style. It's fine if you're looking for advice on how to write unsafe, but most people probably just need to be reminded to use if let Some(x) = x over x.unwrap(), that sort of thing.

3 Likes

Yes, not every area may be recommended. This may be too-long and higher-level than you asked for but these are just some ideas I find useful for myself as a beginner.

What I was thinking about:

(...) the standard library is written to be casually perused. Clicking on interesting things should generally lead you to interesting places.

And also,

While you are looking at the top of the page, also notice the “Source” link. Rust’s API documentation comes with the source code and you are encouraged to read it. The standard library source is generally high quality and a peek behind the curtains is often enlightening.

Rust requires one to get accurate with the terminology; carefully read the compiler errors and so on. This isn't source code, but I point to the same attitude for the std.

For example, some expressions have pattern counterparts with the same or different name and similar syntax.

Correspondingly, when checking the std it's quite useful to look at high level details first. For example, string links to Methods from Deref<Target = str> because the methods will dereference and run that when it does not exist in String. So that may be a good design pattern.

In any case, my recommendation is simply to start in the main page of std and then start clicking on areas you find interesting, and then in the source code.

1 Like

he argues that when the level of competence is not very high, a codebase drifts into “default Rust” - heavy use of Arc/Mutex, RefCell, etc..

I haven't watched the video you referenced. But I hope it does not deter individuals or companies from using Rust. I have to deal with a large legacy codebase written in "default Python". It is so difficult when you are unsure of the types of parameters or return values. Or unsure of the contents of a dictionary getting passed around. Then you rely on the test suite to catch any mistake in your assumptions. But in "default Python" the test suite, though large and slow, doesn't cover enough, and bugs get shipped to production that should have been caught. I think I would much prefer "default Rust" over "default Python", as long as that doesn't include overuse of the unsafe keyword. I think I could refactor "default Rust" with more confidence.

So along with the others, I say, please don't worry too much about "doing it wrong". Go ahead, write Rust code, and find out from experience when to use Rust's smart pointers vs. references, when you need interior mutability via RefCell, etc.

4 Likes

I know my response is coming quite late to this thread, but I thought I'd chip in with some example code and a response to the above concern.

Types can indeed get "complex" -- complex to read, complex to write, complex to map to other subsystems sometimes, etc. However, consider the alternative approach: for a given problem solution, simpler types invariably always results in more complex code or vice versa.

Consider a GUI library that I want to write and finish some day, which I call ROSE. As GUI libraries go, this is by far the most "Rusty" code I've experienced anywhere. Event processing is entirely unique as far as I can tell, and made possible thanks to some of Rust's types. The readme.md file will kind of set the stage for why I started writing it, but take a look in the apps directory for some example code.

Of note, there is a distinct lack of any Rc, Arc, RefCell, etc. types. There is a single Box'ed type representing the currently running application; however, that was borne out of frustration and in some sense laziness on my part.

Note that the goal for this code was not the elimination of these kinds of data types; rather I wanted code that maximized the compiler's ability to detect program errors. Rc<RefCell> relies in part on run-time checking, which I didn't feel I wanted at the time. So that dictated how I built the code, the event handling logic, everything. Note how different it is to, say, a Qt app, or a Gtk application.

It's great for simple applications; however, as I build more complex programs with it, the code can get pretty hard to follow. The GUI state of your application ends up sitting in a single structure, there is a very sharp distinction between drawing a widget and responding to input events from it, etc.

From a certain point of view, this is simpler code. But from others, it's vastly more complicated. I personally like it. But I suspect others who review it will follow up with just how horrible my code really is.

So, remember, some things are just inherently complex, and the type signature might reflect that. It's OK. Because if you bend over backwards to avoid those complexities, you might end up with a program that is hard to maintain in ways you didn't anticipate at first. Complexity shifts around, like an air bubble in a blister pack. :slight_smile:

Hope this helps you out in some way.

7 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.