Skip to content

Make the Monty::new borrow the Uint #600

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

Closed
wants to merge 2 commits into from

Conversation

dvdplm
Copy link
Contributor

@dvdplm dvdplm commented May 30, 2024

Change the Monty trait's new method to take a ref to the Integer instead of ownership.

Fixes #599

@tarcieri
Copy link
Member

@fjarri I'm guessing this will need changes in crypto-primes

fn new(value: Self::Integer, params: Self::Params) -> Self {
BoxedMontyForm::new(value, params)
fn new(value: &Self::Integer, params: Self::Params) -> Self {
BoxedMontyForm::new(value.clone(), params)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I know I already hit approve but this has me second guessing if it's worth it. MontyForm is a Copy type but BoxedMontyForm is a heap-backed type and this is adding another heap allocation which could otherwise be avoided.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah my heart sank a bit too when I had to do this. Then I figured that 1) a Box is cheap to clone and 2) the unboxed variant is probably what users that care about performance would prefer, so perhaps it makes sense to accommodate them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The heap allocation is a tangible performance hit, whereas passing a Copy type by reference may have no performance impact, particularly with inlining

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a user of the API before this PR I find that I end up having to clone my Integers more often than I'd like, given that MontyForm just reads the data. But people instantiating with BoxedMontyForm will need the same clones in their code yeah? It's less annoying for them I guess, because if they read the code they see that the value is actually mutated in place.

At the end of the day I think it comes down to what the API is trying to communicate. Taking ownership of the arguments signals that the users aren't supposed to re-use the values, but when it comes to "number types" I think the expectation is that you can actually continue using it (which is the case for Copy types of course).

Maybe this is tricky to decide because the underlying impls are so different. Would it make sense to try to refactor BoxedMontyForm::new to take a ref and then do the minimum requried amount of copying?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you cloning a Copy type?

Copy link
Contributor Author

@dvdplm dvdplm May 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I'm using it in generic code, through the Integer trait (and the Monty associated type) so I don't know if my users are going to use it with MontyForm or BoxedMontyForm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aah yeah, that's a good point

@fjarri
Copy link
Contributor

fjarri commented May 31, 2024

My personal approach is to take by reference the arguments that are going to be processed in some way, and by value the ones that are going to be used verbatim (e.g. saved in a struct). So for this method I would vote for passing the argument by reference.

But in the boxed case, while the value of the integer is not used verbatim, the heap memory where it's stored is. I can see the value of that to avoid an allocation. Would it be useful to have two new() methods - one that takes a reference and one that takes a value? new(&) and new_consuming() or something?

@dvdplm
Copy link
Contributor Author

dvdplm commented May 31, 2024

I quite like having two separate initializers, reflecting more explicitly what is going on under the hood.

@tarcieri
Copy link
Member

Two initializers where one just calls clone() for you? I think it would be simpler to have one and let the caller clone if need be, which I guess is the current state of affairs.

(When I made my original comment about changing this to a reference, I guess I forgot that BoxedMontyForm::new doesn't borrow and tries to reuse the memory to avoid an allocation)

@dvdplm
Copy link
Contributor Author

dvdplm commented May 31, 2024

Fair enough! Thank you for taking the time to hash it out. :)

@dvdplm dvdplm closed this May 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Monty::new takes values, but impl takes ref
3 participants