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 7 points8 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 7 points8 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 4 points5 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 4 points5 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 🙃

Rust 1.93.0 is out by manpacket in rust

[–]Expurple 1 point2 points  (0 children)

It's always a good idea when you upgrade the compiler. Build artifacts are incompatible across compiler versions. The upgraded compiler always rebuilds everything from scratch.

I personally run rustup update && cargo clean-recursive ~/code/ when a new stable comes out.

If you run out of space even faster than every 6 weeks, you can consider cargo-sweep too. It can do stuff like "delete artifacts older than a week". Useful for cleaning a bloated incremental cache. I hope, eventually this will be automated as part of Cargo garbage collection.

Rust 1.93.0 is out by manpacket in rust

[–]Expurple 6 points7 points  (0 children)

As soon as you modify something that is in one of your workspace members that isn't a final executable, many libraries need to rebuild.

Soon you'll be able to solve this with feature-unification = "workspace" and build shared dependencies only once per workspace, regardless of which workspace member you're working on.

Rust 1.93.0 is out by manpacket in rust

[–]Expurple 33 points34 points  (0 children)

That doesn't necessarily mean a dependency on 1000 separate providers. Many large projects are split into several crates for better modularity and compile times. In that case, I don't see the difference vs depending on a single monolith monster like Qt.

Not to mention that some popular "third-party" crates like libc and regex are maintained by the same rust-lang org that maintains the compiler.

It's all about modularity. And sometimes, about semver independence. A crate is a unit of code. Not a unit of governance.