-
Notifications
You must be signed in to change notification settings - Fork 543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Switch the API away from Borrow bounds #2500
Comments
There is a way to convince the compiler
|
Apparently, |
|
@omni-viral it is better because |
Interestingly, TL;DR: no solution is good atm?
@gankro - maybe you can make a recommendation for us? |
This stuff is extremely out of cache for me, but yeah in general you can't "win" the generic borrow game. The ideal system has conflicting blanket impls, and is consequently inexpressible. I also don't know enough about your system to suggest a more subtle solution. The only advice I can give is "trying to give a million meta-conversions to smooth over APIs is something I dislike as it blows up compile times and makes it much harder to read signatures, so maybe don't do it?" |
@kvark you missed my point. |
Agree |
This doesn't appear so hopeless to me. Basically, it's a matter of communicating to Rust that in our particular case in
Basically, we have a bunch of API entry points that receive sequences of references to our types. These are associated types of struct Foo<B: hal::Backend> {
raw: B::Foo,
_something_else: Bar,
} So as it turns out, neither
I don't find this advice applicable. We aren't going for that type complexity because we feel like it, we see it as the only means of having zero run-time overhead. In this context, compile times are not nearly as important. |
The other option is to not use struct Foo<B: Backend> {
raw: B::Foo,
} you'd write struct Foo<F> {
raw: F,
}
impl<F> Borrow<F> for Foo<F> { ... } Then function signature trait Device<B: Backend> {
fn takes_foos(_: impl IntoIterator<Item = impl Borrow<B::Foo>>);
}
// This should typecheck.
let foos: Vec<Foo<B::Foo>> = ...;
device.takes_foos(foos);
device.takes_foos(&foos); |
I wrote up a detailed explanation here of why you can logically reason about the non-existence of the overlapping implementation, but in fact it can exist, and Rust doesn't factor in this kind of "local non-existence": https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=b0e9517c0599b080f9eeae3bfe548aa2 |
Oh also, although streaming iterators aren't compatible with iterators/for, you can make them, they work fine: https://docs.rs/streaming-iterator/0.1.4/streaming_iterator/ |
@gankro @omni-viral I'm really puzzled as to why this gets a pass: trait Bar {
type Something;
}
struct Foo<B: Bar, S=<B as Bar>::Something>(S, PhantomData<B>);
impl<B, S> Borrow<S> for Foo<B, S>
where
B: Bar<Something = S>,
{
fn borrow(&self) -> &B::Something {
&self.0
}
} Isn't saying that |
So
which you can write in finite characters, but:
|
filed rust-lang/rust#56804 just to be sure this isn't "accidentally" working |
@kvark |
Could this be solved by a custom pub trait GfxBorrow<T> {
fn borrow(&self) -> &T;
} And manually implemented it for all the types for which it makes sense? |
@madadam the point of |
Sure, but is that different from the situation now, where they have to implement |
@madadam yeah, I suppose that is mostly the case. |
The custom trait can be implemented for those types too. The idea is just to explicitly not implement it for |
Funny thing is - we do need that blanket implementation for |
No :) What I'm trying to suggest is:
Point 1 is tedious, but it could be handled by a macro or custom derive. We could even provide custom derive to handle point 3, but that is probably overkill. |
We have a |
I see. Then I think I'm out of ideas 🙁 |
This would be deprecated by #2862 |
It is a very common pattern in gfx-hal API right now to have
I: IntoIterator
andI::Item: Borrow<Something>
. Unfortunately, this falls apart if the user actually wants to have something like this:Compiler isn't happy, because
T
implsBorrow<T>
and there is no way to convince the compiler that this implementation doesn't conflict with our new one...I'm going to change everything to use
AsRef
therefore. Any thoughts? Objections?The text was updated successfully, but these errors were encountered: