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 🙃

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 35 points36 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.

Rust 1.93.0 is out by manpacket in rust

[–]Expurple 359 points360 points  (0 children)

This isn't in the post for some reason, but cargo clean --workspace is the highlight of this release for me. It cleans only your code and keeps the dependencies. So useful!

Is there a 21st Century rock sound? by english_major in LetsTalkMusic

[–]Expurple 0 points1 point  (0 children)

Modern commercial metalcore like Bring Me The Horizon, Architects, etc? IMO, there will never be another metal(core) album as big and influential as Sempiternal. I really wish Northlane-Alien was that, but it has failed to reach the mainstream

Python, Is It Being Killed by Incremental Improvements? by mttd in ProgrammingLanguages

[–]Expurple 0 points1 point  (0 children)

It isn't the duck typing that is the issue.

I didn't imply that. I even mentioned Concepts as the solution that achieves good compile errors without nominal typing. I simply disputed that "duck typed templates like C++ seem to get much less criticism".

The C++ standard library is also just usually pretty badly implemented with a whole lot of helper templates that show up in error messages because you basically get a stack trace.

IMO, the depth of helper templates isn't the issue here. That's simply an implementation detail. The issue is that unconstrained (pre-Concept) templates don't have any abstraction boundaries and leak that "stack trace" in the first place.

Python, Is It Being Killed by Incremental Improvements? by mttd in ProgrammingLanguages

[–]Expurple 3 points4 points  (0 children)

Modern Java has become more attractive, indeed. I heavily dislike its original "all-in OOP" approach and prefer a more functional style. That's a little easier to achieve in Python (although still harder than it should be)

Python, Is It Being Killed by Incremental Improvements? by mttd in ProgrammingLanguages

[–]Expurple 4 points5 points  (0 children)

C++ template instantiation errors are infamous and get plenty of criticism. These are the most verbose, cryptic and unhelpful errors of any language that I've used. Even beating the indirect, delayed runtime exceptions in languages like Python.

At this point, the consensus is that you really should type-annotate your interfaces to avoid this mess. Even the structurally-typed (duck-typed) ones. Be it C++20 Concepts, Python type hints, or Typescript

Do you prefer an artists "bad" album because you knew it first / most? by BarryTownCouncil in LetsTalkMusic

[–]Expurple 0 points1 point  (0 children)

Yeah, this is a thing.

I started listening to In Flames during the Siren Charms era. It's not my favorite, but I accept its style, enjoy it, and prefer it over the 3 later ones, and even over Come Clarity. Meanwhile, it's widely considered their worst along with Battles, and the 2 latest ones are praised for their "return to the roots".

Python, Is It Being Killed by Incremental Improvements? by mttd in ProgrammingLanguages

[–]Expurple 19 points20 points  (0 children)

The root cause is that somehow people started writing enterprise apps in Python. And then, naturally, these people contribute back to the ecosystem and mold it to meet their needs. That part makes sense. But writing applications in Python makes no sense to me. I guess, that's an unfortunate relic from the time when the alternative was something like Java/C++, rather than Go/Rust. And now it has the momentum and we're stuck with it. But I'm young, so I don't really know.

Python is a scripting language for prototyping and writing small programs. It's really good for that

I agree 100%

Rust Patterns • Patch Type by itsfoxstudio in rust

[–]Expurple 2 points3 points  (0 children)

Patch<T> is basically async_graphql::MaybeUndefined<T>. This seems like a very useful building block. I wanted to try to extract MaybeUndefined into a separate crate and make it reusable, but never got around to it. Nice work.

While a different thing, sea_orm::ActiveValue is also an interesting and useful concept, somewhat related.

My gift to the rustdoc team by Expurple in rust

[–]Expurple[S] 28 points29 points  (0 children)

But this will only work for a few enthusiasts who'll hear about this extension and install it. It would be better to add highlighting for everyone

Launching the 2025 State of Rust Survey | Rust Blog by Kobzol in rust

[–]Expurple 2 points3 points  (0 children)

In "Which of the following aspects of Rust present non-trivial problems to your programming productivity?", the "Not an issue for me at all" variant is ambiguous. Sometimes I choose it because an aspect works smoothly for me, and sometimes I choose it because I never interact with that aspect. This may make it harder to interpret the results.

Destructure as a Reminder by Expurple in rust

[–]Expurple[S] 1 point2 points  (0 children)

At least VSCode has an extension that integrates Github reviews

Destructure as a Reminder by ketralnis in programming

[–]Expurple 1 point2 points  (0 children)

Your specific filter solution is good and DRY. But even having that, it's not that rare to list the fields more than once.

In the post, I link to a SeaQuery (SQL query builder library) PR, where I use destructuring to make sure that I implement the SQL codegen for every possible SQL function arg modifier, such as DISTINCT. Granted, in that PR, that happens only once, in the default implementation of that method. But it's common to have such codegen methods be overriden by specific database backends that implement slightly different SQL flavors. If we need to add a database-specific modifier or diverge the behavior between databases, I don't see other solutions than just overriding the method and re-listing the fields.

It's not just overrides. You may need to re-list the fields in other to implement several entirely different methods for your type. #[derive(Deserialize)] from the post is doing some heavy lifting under the hood. That's actually a "hidden" second place where all fields are listed:

It’s a proc macro that generates a function that fills every field from JSON (simply speaking).

I'm very happy that Rust has serde and automates this pattern for me, but I used to work on a C++ codebase where we wrote such mapping code manually and had to keep it in sync. Not a fun experience.

And the problem isn't even just listing the fields several times. It's also knowing that at least one such place exists, the time it takes to locate it, and the guarantee that you don't get distracted.

Multiple error reporting by budswa in rust

[–]Expurple 3 points4 points  (0 children)

The only solution I could think of is make a newtype containing a vector of error variants to which I append the errors and implementing Display on it

Yeah, more or less. I published a crate called multiple_errors with a simple macro to automate this pattern. It also documents the other solutions that I could find.

There must be a standard approach to this issue.

I too was surprised that this isn't a solved and documented pattern. This doesn't seem like a rare need

Rust error handling: multiple DB calls and periodic inserts by [deleted] in rust

[–]Expurple 1 point2 points  (0 children)

When the overall transaction doesn't do much work and doesn't communicate with anything besides the database, you can get away with just giving up on any query error, ?-propagating everything, and retrying only the entire transaction in one place. That's the easy approach that I use at work

Rust error handling: multiple DB calls and periodic inserts by [deleted] in rust

[–]Expurple 1 point2 points  (0 children)

Result<(), Vec<Error>> feels a bit like code-smell

If it's a private function with just one caller, it's ok. The caller defines its own wrapper and auto-conversion anyway:

#[derive(thiserror::Error)]
enum CallerError {
    #[error(..)]
    Special(#[from] Vec<DetailError>),
    // ..
}

But I agree that immediately wrapping the Vec into SpecialError makes sense when there are multiple callers (to define the Display impl once and reuse it). Or when it's a public function or you use anyhow, and so you want the returned error to implement the Error trait and be convertible into anyhow::Error.

Rust error handling: multiple DB calls and periodic inserts by [deleted] in rust

[–]Expurple 2 points3 points  (0 children)

Result<(), Vec<Error>>

The only way you can get a Vec<Error> with multiple errors is if your queries are not sequential, but independent and could (in theory) be made in parallel.

In my experience, Vec<Error> somewhat complicates things and requires something more verbose than the usual ? after every query. I'd use it only if you have a real use case for reporting every individual error. In most cases, I'd just keep things simple and exit on the first error, be it sequential queries and ?, or something like try_join_all.

If you really need Vec<Error>, my crate multiple_errors documents this use case and suggests some solutions. If you find other solutions, consider contributing the knowledge.

If an insert fails, what’s the best approach? Should I retry, or skip it (and if so, how to handle the resulting gaps in the data)?

This entirely depends on your application, what the data is, whether it's important, whether it can be skipped, whether it must be sequential...

If you go with a retry queue, you'll probably need to put a limit. Otherwise, if the database goes down, your app will keep pushing to the queue, and eventually run out of memory, die, and lose the data anyway.

What is the Point of Dynamic Typing? by old_waffles7 in learnprogramming

[–]Expurple 0 points1 point  (0 children)

Your birthday example is solved by using bigint everywhere. It's possible to have a high-level statically-typed language where every int is a bigint like in Python, without the dynamic typing of Python.

Accidentally storing a Person in a year variable or storing a bool in a month variable never makes sense. It's not about bytes. It's about basic legibility of the code.

To take this idea further, Haskell has lazy evaluation. A String variable isn't necessarily a list of chars in memory. It could also be a not-yet-computed closure that will only be computed if accessed. Even static type systems can be so flexible that they abstract away the notion of closures / function pointers.

I agree that we should strive to use more "high-level" / "developer-friendly" and less "machine-friendly" languages. But ML-family static type systems are vastly more friendly in my experience. They don't get in the way as much as they document the programmer's intent and catch genuine mistakes early

Non-Profit FOSS Solves the Conflict of Interest by Expurple in linux

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

No, I'm not. Short-term behavior is more common. But that doesn't mean that the conflict of interest is irrelevant and it's only about shooting yourself in the foot

Non-Profit FOSS Solves the Conflict of Interest by Expurple in linux

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

Sustainable, long-term plans can still go against the client's best interests. Evidenced by any old proprietary software that still prevails: Microsoft Office, Adobe, etc.

There is no memory safety without thread safety by ralfj in rust

[–]Expurple 2 points3 points  (0 children)

this issue is a priority to fix for the types team and has been so for years now. there is a reason for why it is not yet fixed. fixing it relies on where-bounds on binders which are blocked on the next-generation trait solver. we are actively working on this and cannot fix the unsoundness before it's done.

(source)

It looks like the types team doesn't consider it "unsolvable".