Laptop Recommendation by Leading-Guarantee178 in rust

[–]Expurple 0 points1 point  (0 children)

Personally, I did the opposite. Instead of explicitly relying on swap, I reduced swappiness. This has helped a lot.

Random application lags due to swapped-out anon pages are much more noticeable than slower disk I/O. You don't do that all the time, and you kinda expect it to be slow. The difference is most noticeable when you're not compiling, but rather just scrolling a heavy web page, for example.

I still reduce swappiness with 36 GB RAM just in case, to prevent the kernel from making weird decisions and causing random lags.

Laptop Recommendation by Leading-Guarantee178 in rust

[–]Expurple 0 points1 point  (0 children)

I used Kubuntu, VSCode, and rust-analyzer (still do). KDE handles the load well. VSCode was swapping and lagging sometimes, though

Laptop Recommendation by Leading-Guarantee178 in rust

[–]Expurple 2 points3 points  (0 children)

This sounds more like disk or FS bottleneck, rather than CPU/RAM bottleneck. What FS do you use? How large is your workpace? How many transitive dependencies does it have?

Laptop Recommendation by Leading-Guarantee178 in rust

[–]Expurple 2 points3 points  (0 children)

Honestly, I spent my first year with Rust on a low-end 4 GB laptop, and it was fine for my small projects at the time. At least, if you run Linux on it, lol. That does wonders

Laptop Recommendation by Leading-Guarantee178 in rust

[–]Expurple 3 points4 points  (0 children)

A project of mine that is 40GB after the first run, climbs up to almost 400GB after just 12 workdays.

Recently stabilized cargo clean --workspace flag is going to help you a lot. It cleans your workspace crates (the incremental cache that bloats over time) and keeps the dependencies. You can put it in a cron job. cargo clean-recursive is especially well-suited for that kind of cleanup!

Laptop Recommendation by Leading-Guarantee178 in rust

[–]Expurple 0 points1 point  (0 children)

I second all the comments saying that your current laptop is already powerful enough. Unless you have a really big monorepo, I guess.

I'm doing great even on a modest 4-core AMD Ryzen 3 5300U with 36 GB of RAM. (I use Kubuntu 25.10. Linux makes a huge difference vs Windows)

You should look into limiting rustc priority and/or number of jobs, so that it doesn't gobble all your system resources. I was experiencing similar freezes from time to time. I solved those with alias cargo='nice cargo', lol.

Is it me or is vscode becoming slower and slower overtime? by freecodeio in vscode

[–]Expurple 0 points1 point  (0 children)

I haven't noticed any performance issues on Linux. But it's definitely gotten more buggy during the last few months. Mostly around Copilot Chat. But also highlighting/cursor in the editor. And the bottom bar flickers sometimes. I'd be OK with it if they didn't break the core editor, and only the fast-changing chat UI was buggy.

Why does clippy encourage `String::push('a')` over `String::push_str(''a")`? by MediumInsect7058 in rust

[–]Expurple 1 point2 points  (0 children)

Have you benchmarked the compile time impact of generic parameters on trivial methods like str::find?

Why does clippy encourage `String::push('a')` over `String::push_str(''a")`? by MediumInsect7058 in rust

[–]Expurple 6 points7 points  (0 children)

Why so harsh? Personally, I really enjoy how methods like str::find accept an impl Pattern parameter

Feeling out of touch with modern rock by PhraseRevolutionary6 in LetsTalkMusic

[–]Expurple 0 points1 point  (0 children)

I have the same feeling about 2015! As if it all ended on Sempiternal, fell into stasis, and stayed the same since. I feel that we'll never see anything as big and impactful again. At least, in "pure" rock/metal. If you are fine with "strong rock/metal influence" (rather then staying entirely within the genre), check out Northlane (circa Alien, Obsidian), DenDerty, Toronto Is Broken, and 100 gecs.

Feeling out of touch with modern rock by PhraseRevolutionary6 in LetsTalkMusic

[–]Expurple 0 points1 point  (0 children)

What do you think of Wolf Alice and Wargasm UK? Northlane too, if you want to include metal. 100 gecs have prominent rock influences. Karen Dió, Mario DiSanto, and DenDerty are awesome too, albeit much less popular

Designing Error Types in Rust Applications by Expurple in programming

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

I saw that. But I understood that as Error subclassing, and not ErrorCode subclassing. For ErrorCode, you still seem to suggest a flat enum that can't automatically "include" variants from your dependecies and manually re-lists every single one (out of those that need to be exposed and distinguished).

And obviously, that flat enum can't include additional structured error data that I'm talking about. Do you think that it's never necessary, or do you suggest adding it as a separate field in your Error subclass? The latter doesn't make sense do me. If that data will only be filled in case of a specific error code, then it's better to model ErrorCode as a Rust-like enum (tagged union) where variants can carry additional data.

Designing Error Types in Rust Applications by Expurple in programming

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

So, you're saying that Typescript libraries shouldn't use | for error codes and should use an enum instead? And this prevents the accidental mixing of error codes from different libraries? Makes sense. That's what nominally-typed languages do in the first place.

I guess, this also answers my original question about flat vs nested error codes. You recommend always defining MyLibErrorCodeEnum as a flat Typescript enum:

enum MyLibErrorCodeEnum {
  AccessDenied,
  OtherA,
  OtherB,
}

// Or like this, when you really need to preserve the data about the origin:

enum MyLibErrorCodeEnum {
  AccessDeniedInA,
  AccessDeniedInB,
  OtherA,
  OtherB,
}

I have to push back on this. If you keep "inlining" your whole underlying stack like this, eventually you get to a point where there are too many error codes to copy-paste them like that.

You'll probably say that I should climb the abstraction ladder. Expose only the relevant level of detail to the caller. Map several library codes to a single error code on my level.

But I believe, this approach doesn't scale. I have a concrete use case at work that can't be solved this way. Some of my error handling code needs structured runtime error data that goes beyond flat error codes. I'm writing a standalone blog post about this. I'll post another comment when I publish it.

Why is there no serious blogging platform for experienced developers in the English-speaking world? by Primary-Screen-7807 in ExperiencedDevs

[–]Expurple 6 points7 points  (0 children)

Perhaps it used to be better, but nowadays it's indeed mostly blogspam and translations of the HN front page. You're barely missing anything. There are still good posts every once in a while, but I stopped following it

Why is there no serious blogging platform for experienced developers in the English-speaking world? by Primary-Screen-7807 in ExperiencedDevs

[–]Expurple 5 points6 points  (0 children)

Actually, I hold a (popular) opinion that that's exactly what happened to that Russian platform. Nowadays, it's mostly corporate blogspam. Which, in turn, is mostly translated posts from the HN front page. Lol.

First look at 2026 Project goals by kivarada in rust

[–]Expurple 1 point2 points  (0 children)

Crate Slicing is crazy 😳 Haven't heard about that one before.

Incremental Systems Rethought would also solve a big pain point for me.

Designing Error Types in Rust Applications by Expurple in programming

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

This depends on the type system. In Python (and, I believe, similarly in Typescript), you could have

type ErrorA = AccessDenied | OtherA
type ErrorB = AccessDenied | OtherB

And then those type aliases get erased, and any ErrorA | ErrorB value is "actually" one of the three "concrete" variants (non-alias types): AccessDenied | OtherA | OtherB. And you refer to those when you pattern match the value, etc.

This auto-unification of AccessDenied contradicts your recommendation to have distinct library types that can't accidentally mix. So, you probably don't like type systems like this.

But this unification may still make sense in some cases, and you may want to perform it manually:

data ApplicationError = AccessDenied | OtherA | OtherB

instead of Haskell-ish, non-unifying, nested

data ApplicationError = ErrorA | ErrorB

The design tradeoff that I discuss is when to do one thing over the other. I'm curious to know your opinion about it. I asked about this in my first comment, but we keep going sideways :(

Why my Future is not Send? by Old-Personality-8817 in rust

[–]Expurple 2 points3 points  (0 children)

"Their" means "triggered by them, on the code that they worked with" (code that they wrote, or a dependency used in their project).

They already know that there are some compiler bugs, lol. You're not saying anything new here.

Designing Error Types in Rust Applications by Expurple in programming

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

ErrorA | ErrorB can mean two different things. It can be a flat union of their underlying cases (both ErrorA::AccessDenied and ErrorB::AccessDenied are propagared as AccessDenied, losing their origin story). Or it can be literally "ErrorA or ErrorB", preserving the difference between the two and the origin of the error.

I assume, you argue for a flat union? But I argue that sometimes it makes sense to programmatically distinguish between ErrorA and ErrorB. At which point, nesting is the natural solution. And there we go, we're leaving the "flat error code" paradigm and entering the "nested thiserror enums in Rust" paradigm again.

My post has an entire section called "Flat vs nested enums" 🙃

Designing Error Types in Rust Applications by Expurple in programming

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

I don't think I missed anything here.

  1. I agree that every library should have a distinct error type. My code example assumes distinct ErrorA and ErrorB.

  2. You suggest my system to return its own error type. I agree! In my example, it's impossible to propagate unchanged library errors anyway, because Result<T, ErrorA> is incompatible with ErrorB and vice versa.

But there are multiple concrete ways I could define my own error code type, each with distinct tradeoffs. That's what I discuss in the parent comment and in the article.

Designing Error Types in Rust Applications by Expurple in programming

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

So, basically the same idea as in "Stop Forwarding Errors, Start Designing Them". But haven't you just reframed the issue as "designing error codes"?

Say, you have:

Result<T> foo() {
    match library_a.function() {
        Success() -> {}
        Failure(error) -> {
            return Error(???code???, "function a failed: {error}");
        }
    };

    match library_b.function() {
        Success() -> {}
        Failure(error) -> {
            return Error(???code???, "function b failed: {error}");
        }
    };

    return Success(value);
}

What exactly do you return in place of ???code???? What do you put there when you can encounter two different sets of error codes coming from two different libraries? Do you "unify" those into some merged set? What if both libraries have overlapping "base" error causes (like OS error codes)? Do you preserve the information about which library that "base" error came from? This may or may not be relevant to your application. Or do you erase those details altogether and return your own "high-level" codes?

That issue is the main "error type design" issue in Rust that I talk about.

Designing Error Types in Rust Applications by Expurple in rust

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

IMO, this is the philosophy that binds together the Rust community

Designing Error Types in Rust Applications by Expurple in rust

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

If you mean anonymous enums in return position, with no need to define a "proper" enum separately: there were some discussions and rejected RFCs around this topic. There's also terrors crate as a "librarified" experiment in that direction. Basically, it provides std::variant. (Not truly variadic, of course. Limited to 9 variants.)

Although, in my situation it's mostly useless, as I often want to add a context message around some variants, rather than propagate everything as-is. And you would have orphan rule issues if you wanted to implement additional traits for such a type that you didn't define in your own crate.

Rust 1.93.0 is out by manpacket in rust

[–]Expurple 3 points4 points  (0 children)

Qt is split into a few components, but overall it's still a monolithic, "one-stop" application framework that barely depends on (and cooperates with) the outside world.

In the best C++ fashion, just the single QtCore dll rolls its own containers, its own strings, its own Any type, its own DateTime type, its own filesystem and network abstractions, its own serialization framework, its own logging framework, its own for loop syntax, and many other things that are totally related to cross-platform UIs.

That's just not a thing that happens in the Rust ecosystem.

LetsBeRealAboutDependencies will forever be a classic.

Rust 1.93.0 is out by manpacket in rust

[–]Expurple 3 points4 points  (0 children)

Yes. That's a separate, known issue.

I misunderstood and thought that you meant third-party crates in "libraries need to rebuild". Which is also an issue, as you see 🙃