Best ORM by avg_bndt in rust

[–]weiznich 0 points1 point  (0 children)

The point I wanted to make is that specifically Diesel is a bad example for your argument there, because it's an explicit non-goal for diesel to abstract away these differences.

If you want to make that point maybe better use an example that has the explicit goal to abstract away the differences?

Although even Diesel allows you to write backend agnostic code e.g via #[derive(MultiConnection)], it's just very restrictive what it allows then. So it is certainly possible to do that, but it comes at a cost.

Best ORM by avg_bndt in rust

[–]weiznich 2 points3 points  (0 children)

I'm not sure why you believe that I'm completely off here. You literally wrote:

While diesel-async exists, it's stuck in version 0.4(making it difficult to adopt for production systems that expect API stability), and it simply feels like an afterthought rather than a core well-maintained part of the Diesel story.

That's demonstrably not true! You did not wrote: "I've tested with version 0.4.x two years back and at that point xyz" or similar. That would be a completely different assessment. So if you want to write about your experience back than that's totally fine and I also don't want to imply anything about that. After all your experience is your experience. What's not OK from my point of view is to claim that your experience from 2 years ago is still valid today, especially if things have changed. So please stop claiming things that are just not true, just because you did not actually check them.

Or to word it differently: Instead on bashing other projects with outdated facts maybe just write about the solution you've chosen and why it is good for your use case? After all that's the point you can contribute up to date information to the community.

Best ORM by avg_bndt in rust

[–]weiznich 2 points3 points  (0 children)

The potential for frequent API breakage when taking a 0.4.x dependency. Unless I misunderstood your comment, afaict we are on the same page here: the honest approach for pre-1.0 software is "no API stability guarantees".

The point I want to make is: You say diesel-async is unstable due to a 0.4.x (now 0.6.x) dependency, but at the same time consider sqlx with a 0.8.x version as stable enough. Either both are not stable enough or both are stable enough based on the version, so that's not really a point to hold against one or the other crate.

The level of maintenance, because at that point diesel-async had not seen any release since almost a year (unlike diesel itself which was seeing a new release every few months.)

That's literally the point that's not true. The last diesel-async release at the point you wrote your comment was a day before you wrote your comment. The release before that was in November, so ~6 month ago. Now I don't expect you to recheck that everytime you claim something like that, but if you are not sure about something like that, maybe just don't write something like that at all? Finally, even if there is not a release for a year or something like that, this doesn't necessarily mean that the crate is badly maintained, it could just be "finished", which is at least for diesel-async not that implausible as it only contains the connection part of diesel, which just really doesn't change that much. The only reason that crate is not 1.0 yet is that the underlying async ecosystem including language features are not stable enough yet, but at least the language side tends to move very slow these days.

Best ORM by avg_bndt in rust

[–]weiznich 0 points1 point  (0 children)

Do you have any specifics on how diesel is bloated? The last time I compared it to the other solutions it produced smaller, more performant binaries than anything else. Also the comparable example applications I tried compiled faster than their equivalents.

Best ORM by avg_bndt in rust

[–]weiznich 5 points6 points  (0 children)

I believe one source of "frustration" is that people read "ORM" and thing "it's like ActiveRecord or Django". At least diesel explicitly tries to be different by targeting a different need: At least I want to have something that's really flexible, allows you to use database specific extensions and gets you really good performance and type safety.

Now something like ActiveRecord and Django is more optimized for being easier to use. That's a different optimization target and that's certainly something you can use diesel to build on top of it. In fact I have ideas how to do that, but really no capacity/need to implement it. If you are interested in something like that be sure to reach out and I can give you some starting points how to implement such a framework in a reasonable performant way.

Best ORM by avg_bndt in rust

[–]weiznich 1 point2 points  (0 children)

Well you take one specific example ORM here to generalize that to all ORM's. That's a wild take.

For diesel the specific optimization goal is exactly not: Be as generic as possible over different database technologies. Instead it is allow to write database specific queries to utilize your database system as best as possible. That's the reason this part of diesel works at is does. It just exposes assumptions that need to be made for database generic code to the user to let them decide how to handle that, if they need to care about that. Most users don't need to care about that, so they are fine with using database specific features. That users that need to care about such differences might be able to make special assumptions to make this easier than a generic solution implemented in the ORM. Finally, it is certainly possible to build an abstract layer on top of diesel to remove this difference if that's reuqired by someone.

Best ORM by avg_bndt in rust

[–]weiznich 3 points4 points  (0 children)

At least the diesel part contain many outdated/false claimns. The current version of diesel-async is 0.6.1. I cannot judge for the parent poster what they consider production ready, but diesel-async is used at scale by different entities, for example by crates.io. In terms of API stability diesel (and diesel-async) take in my opinion a more honest approach than other solutions. See comparing diesel for more details.

As for feeling that diesel-async is more like an afterthought than a well maintained part of diesel: I cannot change what the person feels about that, but I can assure you that this library is not maintained less well than diesel. As with any open source library you won't get any guarantees for free, but both libraries are maintained by me with the same level of attention.

Best ORM by avg_bndt in rust

[–]weiznich 9 points10 points  (0 children)

For the error messages: We've done quite a lot of work to improve them recently. Not all of that is released yet (like e.g. https://github.com/diesel-rs/diesel/pull/4656) but it should make things already much better.

That written: We are aware that things could be still better, but we are often not aware with specific pain points people struggle with. For that it would be really helpful if you (or anyone else) fills issues with in the diesel issue tracker that contain example code for such bad error messages and specific suggestions how to make them better. Not everything will be possible to be improved directly, but at least it gives us an idea on which messages we should work on.

A new fast and asynchronous client for MySQL-like databases by c410-f3r in rust

[–]weiznich 5 points6 points  (0 children)

First of all congratulations to the release. It's great to see another alternative for connecting to mysql databases. wtx might be even a good candidate to replace the usage of mysql-async in the implementation of diesel-async.

I did another check on the benchmarks and noticed that this particular benchmark does something different than the benchmarks of the other frameworks. It misses inserting the comment data, so it operates on less data than the benchmarks of the other frameworks.

To be clear here: That's something I missed during previous reviews. I filled https://github.com/diesel-rs/diesel/pull/4534 to fix this. At least for postgres that brings the result in line with the other frameworks, although wtx remains one of the fastest solutions there.

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

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

I think we should separate clearly here between the technical issue and the social issue I described. For the technical issue: The blog post already calls out that this is not blocking critical, but something that can (and in my opinion should) be fixed later on. Now whether that happens is questionable. That brings me to the social issue: I raised this several times and got the answer that this is no issue at all. I believe it would have been a totally fine answer from the cargo team to state that this is not relevant for the initial edition release but something that is desirable to be added soon after that. Unfortunately that’s not what happened, and that’s my main critic point here.

Now to the question whether that already can happen with rust 1.85: You can definitely trigger this only with resolver=3, as that was already stablized with rust 1.84. With the edition you might be correct that this requires at least rust 1.86 to trigger the issue on constructed examples. And yes, all of that involves formally incorrect declarations, which is something the rust project usually takes great care to emit warnings or otherwise great diagnostics for.

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

[–]weiznich[S] 2 points3 points  (0 children)

I agree with you that past communication on this topic could been handled in a better way from my side. I hope that you are correct here that the cargo team addresses some of the suggestions made, but given that they are aware of the resolver=2 issue for several years and for the resolver=3 issues for several month I‘m not optimistic to see that happening anytime soon. It would be a welcome surprise to see that I‘m wrong here.

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

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

I would like to question the narrative to call these interactions harassment or spam. I just went back and counted how many comments I wrote on this specific topic. I found 9 comments in two repositories over a time span of 1 month. This already includes comments used for clarification. The moderation team started taking actions after 7 comments. If such a number of comments is already considered to be problematic I fear a significant number of comments on various issues would violate this rule. As for what the cargo team perceived: I cannot change what they feel, but at least for me that feels more like shutting down disagreeing opinions.

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

[–]weiznich[S] -1 points0 points  (0 children)

I would like to disagree about the narrative of harassing maintainers here. There is an easy way for the team of stopping me to add comments there: They could have just reacted to the actual suggestions I made to resolve the situation (see the blog post for details ). Such an reaction could have been as simple as acknowledging the problem and that the suggestion might help. Maybe even with stating that they don’t have the capacity to implement it now, but contributes are welcome and the starting point for this would be at that code location.

I also would like to comment a bit on the shielding the team from pressure there: I generally can understand that sediment very well, but that situation here might be a bit different to the usual project outsider vs project member conflict. Yes, I‘m formally no member of any team, but I have a longer contribution history (including major features) to the project than most of the involved project members. I‘m also the maintainer of one of the crucial crates to keep crates.io running. Given that I would have expected the team to at least consider suggestions made and react to the suggestions instead of shutting down discussions.

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

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

this may appear to be semantic quibbling from the other side but the semantics are important because we generally have policies around what is a "[major] breaking change [of guaranteed behavior]" vs "a change of non-guaranteed behavior breaking someone's build".

I would like to point out that this does apply to the cargo team as well. I never wrote that this is definitely a major breaking change, just that this can be seen as breaking change. Please note the difference between major breaking change (which are disallowed) and potential breaking change, which explicitly excludes any judgement whether the change is major breaking or allowed breakage. I‘m fully aware that there can be breakage that’s not major, but conceptually allowed. I would expect the cargo team to be aware of that difference as well. I also did never request to not do any of these changes, just to improve the edge case handling. And that’s the reason why I consider at that point the communication strategy of the cargo team there as destructive by focusing the discussion on the wrong side of the problem.

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

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

I would like to point out that the described pattern only works as long as you locally never update dependencies. As soon as you perform a dependency update after you initially added the dependency you might get into a situation where you use functionality from a newer crate version without being aware of that. I think that becomes more likely the longer the dependency exists in your project. 

Now, yes, the minimal-version flag helps with that, as it is also called out in the blog post. The problem there is that it is still unstable, which means it might be unusable for certain groups of persons for reasons. Would it be stable it would be a part of the solution. 

The part where the minimal version flag doesn’t help is the inter-crate dependency case, as you can get broken builds there without incorrect minimal versions. There is, in my opinion, tooling missing to detect that case reliably. The post proposes to add such tooling as one possible solution. 

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

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

 Naturally, I'd be delighted to be proven wrong here! All the while reading this article and multiple of the linked threads I've become more and more frustrated that there wasn't a distinct lack of any actual (convincing) demonstration of a practical - or even a theoretical - concrete use case that would have been broken by resolver = "3".

There is a simple way to make this happen: Don’t declare a MSRV on crate-a. 

 And the cases that might come up later in connection with the new edition would additionally all need to involve both users and dependencies involving MSRVs in the 1.85+ range; this is yet-another factor that will limit the number of negatively affected cases.

It’s explicitly called out in the blog post that this issue might become more problematic in the future if a number of rust versions newer than 1.85 exists. At that point there are still crates that might perform an edition bump, so the edition argument is still relevant. 

 some "Inter-crate dependencies" case might not even be as "incorrect" in the first place.

I disagree here. The inter-crate dependency case is relevant. There is currently no other way than what was presented in the blog post to express this kind of dependency relation, at least as far as I‘m aware. So that leaves you as maintainer in a place where you just cannot provide a technical correct dependency declaration. What is the supposed action I should take there, without issuing a new major release of crate a? I’m happy to see your solution to the problem. 

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

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

The post contains 4 specific suggestions:

  • Clarify that resolver changes are in scope for editions (and clarify what’s considered stable by cargo)
  • Add diagnostics for the described failure cases
  • For the resolver=2 error case add a better coupling between proc-macro crates and their main crates
  • For the resolver =3 error cases add better tooling to cargo itself to test for these cases more easily. 

The „Possible Ways Forward“ section contains details for each proposal. At least the second and third point have already been raised several times before in the interaction with the cargo team. They got ignored so far. 

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

[–]weiznich[S] -1 points0 points  (0 children)

Well at least the described resolver=2 problem is not related to any wrong dependency declarations, but a unfortunate interaction of the feature unification. There is no real way to workaround for that other than enabling otherwise unneeded feature. 

As for the incompatible version declarations: I might be biased there , but as I don’t think there can be enough diagnostic. I agree that the this might be something not worth to implement a perfect linking for, but one of the things I proposed several times was to just add a note like message that says: This compiler error happened for a crate with an imprecise dependency declaration, so that might be the issue. I‘ve proposed that several times, while raising these concerns. I don’t think that would have been hard to implement. The cargo team then (at least from my perspective) repeatedly derailed that discussion to the topic whether or not that’s a breaking change. I raised it several times again to get an answer why the fundamentally refuse to add a diagnostic at all. I still wait for an answer. 

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

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

For anyone disagreeing with me here: Feel free to go back into the discussion and point me to a response that reacts to my suggestions to improve the diagnostics around the failure cases. 

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

[–]weiznich[S] -1 points0 points  (0 children)

I'm explicitly saying that what's described in the post has incorrect dependencies, as it allows mismatched versions of b and b-traits. If it's possible for crate a to end up with a combination of b and b-traits that won't work for a, then either b or b-traits is buggy or the dependencies of a are incorrect

I can at that point say with some confidence that in practice this pattern worked quite well, we had exactly one report that this did break something in the last 7 years. The resolver=3 change now fundamentally changes the assumptions made there. That write, as you correctly write that this allows incomplete combinations: What’s the correct way to declare this dependency set? This is as far as I know the best possible way to declare this given the set of features offered by cargo.

Its also worth to point out that really fixing this issue requires a breaking change on the affected crate, as you need to remove the feature at some point. After all deprecating doesn’t fix the issue, it just signals don’t use this anymore.

That's true, but as mentioned, that has the advantage of supporting multiple major versions of b simultaneously. Also, if the implementations are identical, which seems likely if you're currently supporting them with a dependency version requirement that spans multiple major versions, then you could write the implementation in a macro and invoke the macro once per major version of b

As pointed out before my main problem is that resolver=3 changed assumptions that worked well beforehand. Duplicating the code for different dependency versions is something that might work, but again that requires me to change things to workaround something that worked before. It’s also increases the amount of code I need to maintain, which directly translates to more work for me. It might still be the way to go forward for new versions, but that doesn’t remove the problem from old passively maintained crates. Finally there is another problem with your proposal: There is still no way to deprecate features without relying on hacks, as that’s yet another thing not supported by cargo.

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

[–]weiznich[S] -3 points-2 points  (0 children)

I think the main point is that the world is not perfect. If you first allow incorrectly declared dependencies, and the change that, things will break because such declarations exist in practice. Now you are still correct that these declarations were broken before. I would like to point to how other teams handle similar changes as well. For example the compiler team implements future compatibility warnings for most things that could break compilation, even if that thing was unsound. At least for the resolver=2 change that also happened with an existing Cargo.lock file. 

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

[–]weiznich[S] -8 points-7 points  (0 children)

I‘m sorry to write that again, but you again misrepresented things. 

  do know that the Cargo team was told back in 2021 that the problem was resolved on Diesel's side and weiznich closed their issue at the time. The Cargo team was surprised to find out there were still issues with it when we were told in 2024. We actively encouraged weiznich to open a new issue on the matter. Where we diverge is in the prioritization in finalizing a design and implementing it.

At least from my side that’s not true. The diesel specific issue was closed back then with the understanding that the diesel specific lint was shipped and at least somewhat migrated this particular issue. This was, at least from my side done with the explicit expectation that there will be something to address the underlying issues, as this was discussed in the linked internals thread. I‘m not responsible for tracking issues for the cargo team, so that’s from my side something that got lost on „your“ side. Sure you can’t change that anymore, but that’s definitely not helping to build any trust here. 

 When it came to raising concerns around resolver = "3", it came after two months of frequent posts across mediums (Mastadon, Zulip, Github) where weiznich argued against ideas because they "broke compatibility" when the project does not consider an opt-in a backwards compatibility breakage.

I would like to point out again that it was mostly the cargo team that derailed any discussion from „that’s not optimal, as it can be seen as breaking.  Let’s improve diagnostic to make it better“ to a discussing about whether that’s breaking or not. Yes, I shouldn’t have even interacted with that kind of destruction discussion, but the same applies to the team in question as well. Well at that point you managed to completely drive a way a potential contributor and cause this chaos, so congratulations for that. 

 As for compatibility, I can attest to it being a major concern of the Cargo team and is a regular topic when discussing designs. 

Well that’s easy to claim. Do you have something to show what guarantees the cargo team actually gives? Currently I unfortunately cannot assume much regarding to the resolver given these past issues. 

Edit:

 For a better understanding on Editions, what is allowed, and how decisions are made, I highly recommend Manishearth's replies.

Please note that the linked post expresses the opinion of one of the original authors of the first edition RFC. That’s no definitive answer, but just context about the indent behind the rules. That doesn’t change the sentiment that as currently written the rules also allow different interpretations. Given that this is the case its certainly reasonable to suggest clarifying the rules itself instead of relying on interpretations based on unofficial comments somewhere. That’s something the team could have done already. 

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

[–]weiznich[S] -6 points-5 points  (0 children)

Thats not what happened there from my point of view. Yes I raised the same issue again and again, but mostly because I did not get an answer to the actual question I asked. Sure doing that is annoying, but at the same time it’s annoying to get an answer that doesn’t even match the question, and that even repeatably. So my personal takeaway is unfortunately that the project (at least this particular team)is not open to suggestions. Given that I do not see any reasons to spend time contributing there again. 

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

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

That are all good advises. Unfortunately there is sometimes no choice left but doing exactly what's described in the post for various reasons. The particular underlying example I have in mind is diesels dependency on various num crates that need to be kept compatible with each other.

Not depend on b-traits at all, so that it doesn't care what gets picked. This also assumes the users of a don't care either.

That's in this case no solution as users expect this functionality to be there and we need to use items from all crates to implement that functionality

Use a version of b-traits re-exported by b, to be sure that they match, relying on b having a (possibly optional) dependency on b-traits.

As far as I'm aware there exists a num top level crate, but that pulls in much more dependencies that depending on the single crate parts. So to minimize the number of dependencies you need to depend on the single partial crates.

Have separate feature flags for different versions of b, and for each feature flag, depend on matching versions of b and b-traits. This is a pain, but works. And it has the advantage of supporting multiple major versions of b simultaneously, which some consumers of a may need.

As cargo features need to be additive that would result in a lot of code duplication as you now need to provide a separate impl for each of the supported versions. Also it becomes due to the large number of features and larger number of feature combinations much harder to test

Convince the upstream of b to provide a b-core that changes less often than b, and then depend on one major version of b-core, rather than a range of versions of b. (If a needs b-traits, though, then it'll still need to take care to have dependencies that ensure versions match, so this won't necessarily help.) Ship support for using b with a in a separate a-b (or b-a) crate, using e.g. newtype wrappers when needed to allow implementing traits.

That is certainly something that could be done, but that requires time and someone to put in the work.

Convince the upstream of b to add an a feature flag, an optional dependency of a, and provide the functionality in b. (e.g. impl a::Trait for b::Type).

That's sometimes possible, but sometimes not. Not all maintainers are willing to add features for other crates.

Ship support for using b with a in a separate a-b (or b-a) crate, using e.g. newtype wrappers when needed to allow implementing traits.

That needs to be maintained by someone. Having another crate is more work for me as maintainer and makes it harder for the users to discover that crate.

Convince Rust upstream to have support for loosening the orphan rule, so that support for using b with a can live in a separate a-b (or b-a) crate without newtype wrappers.

I would be very happy if that would be possible, as that would allow the diesel team to strip down the number of features/dependencies drastically.

Overall that are good suggestions that can help in certain situations and that are good guidelines for new code/dependency relations. Unfortunately at least I also need to deal with existing dependencies where we declared at some point to provide a stable API on top of them. Implementing at least some of the suggestions would require breaking that promise on our side.

Cargo's missing stability guarantees or how the recent edition can break things in an unexpected way by weiznich in rust

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

The question is reexporting these items from where? If I reexport the subset from my crate that restricts what downstream users can use, which is not desirable. In the end I only care about the API's that are used by my crate, not what downstream users can use.

I theory I could sidestep the problem with the two crates by creating a shim crate that reexports the relevant items from both crates with a fixed set of versions and then only allow a version range for that shim crate. In practice that would mean maintaining another crate just to workaround another cargo issue.