-
Notifications
You must be signed in to change notification settings - Fork 193
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
meta: type signature for CryptoRng
s
#1148
Comments
As discussed in RustCrypto/traits#1148, this uses `&mut impl CryptoRngCore` as the API for passing CSRNGs. This removes the need for a generic parameter in the type signature while also keeping syntax to a minimum. The traits in `signature` v2.0.0-pre.2 switched to these APIs. See RustCrypto/traits#1147.
As discussed in RustCrypto/traits#1148, this uses `&mut impl CryptoRngCore` as the API for passing CSRNGs. This removes the need for a generic parameter in the type signature while also keeping syntax to a minimum. The traits in `signature` v2.0.0-pre.2 switched to these APIs. See RustCrypto/traits#1147.
There's an additional problem with For that to work, we need to do one of:
Of these options, I'm now leaning towards number 2, and now understand why the I think this is one of those cases where the overhead of virtual dispatch is insignificant compared to the operation being invoked, which will involve something like a system call (for |
Personally, I prefer the third option and would be surprised to find a But I think, the root issue is on the |
Yeah I'd be fine with the third option too. We need to make a call before we release |
FWIW I also prefer (1) or (3) over (2), because what I'm concerned of is:
What is the result if A calls B calls C calls D, where A and C are using (1) or (3) and B and D are using (2)
So it seems to me that this overhead can accumulate without bound, due to repeatedly introducing wrappers and then type erasing them. And there are a lot of libraries today that just have bounds like I have not looked at actual generated assembly, and I think there are some devirtualization optimizations that can be performed by LTO. But it seems better not to depend on it. My feeling is trait bounds like It seems better for APIs to only declare requirements that they actually need -- if they are okay with a reference to a possibly unsized RNG, which most things are, then why not make that the trait bound, instead of forcing the construction of a trait object. That's my 2 cents, thanks for starting this discussion |
@garbageslam I don't understand your preference for 1/A over 3/C. Reading your bullet point 2 it seems like you're describing B calling A? I'm a little confused.
Except with a Granted |
I'm just trying to imagine that there are a series of alternating calls to functions following option 2 Every time we call an option 2 function, we have to create a trait object if we don't have one already, and every time an option 2 function calls into a non-option 2 function, we're forgetting / type-erasing that there is a trait object in there already. So it seems like we could create a lot of trait objects on the stack this way and have a lot of virtual dispatch introduced. Here I'm assuming that we have a large project, and some functions are using Maybe it doesn't matter for The scenario where there's multiple trait objects is like, |
But aren’t all of those problems the same regardless of if a named generic parameter It feels like six of one, half dozen of another to me there. |
Yeah I think that's right, it doesn't matter if a named parameter If I understand right then the |
As discussed in #1148, adopts a generic paramater `R` for RNGs, and also adds a `?Sized` bound which permits the use of trait objects.
As discussed in #1148, adopts a generic paramater `R` for RNGs, and also adds a `?Sized` bound which permits the use of trait objects.
I just realized we can have both: a much more lightweight syntax and support for trait objects. use rand_core::CryptoRngCore;
pub fn foo(mut rng: &mut dyn CryptoRngCore) {
bar(&mut rng);
}
pub fn bar(_rng: &mut impl CryptoRngCore) {
} That leverages the blanket impl of |
@tarcieri |
I opened #1183 to move |
Alias added in `rand_core` v0.6.4 with a blanket impl for `CryptoRng + RngCore`. Using a mut reference avoids reborrowing. For more context, see RustCrypto/traits#1148.
Alias added in `rand_core` v0.6.4 with a blanket impl for `CryptoRng + RngCore`. Using a mut reference avoids reborrowing. For more context, see RustCrypto/traits#1148.
I now pass |
@burdges check out Hopefully the next release makes |
In the upcoming releases we will use |
In #1087 we discussed various possible type signatures to use for RNGs.
We currently use
impl CryptoRng + RngCore
, leveraging a blanket impl ofRngCore
for&mut R where R: RngCore
.This has some ergonomic problems in that confuses users who aren't aware of the blanket impl about what exactly to pass. The flipside is it permits some nice syntax like directly passing
OsRng
instead of&mut OsRng
as a caller.However, for the receiver it requires reborrowing the
rng
as&mut rng
everywhere if therng
is used more than once. Themut
also needs to be present on the local variable binding, so really the only thing it gets rid of is&
.rand_core
v0.6.4 introduced aCryptoRngCore
marker trait with supertrait bounds onCryptoRng + RngCore
, as well as a blanket impl for any types which implCryptoRng + RngCore
.This allows writing
impl CryptoRngCore
instead ofimpl (CryptoRng + RngCore)
.In #1147 I'm trying out
&mut impl CryptoRngCore
which minimizes syntax as well as the drawbacks for the receiver (this will be in a prerelease with the option to tweak it prior to a final v2.0 release).Regardless of what we pick as a new convention, I think we should use the same convention everywhere.
The text was updated successfully, but these errors were encountered: