Skip to content

Use &mut self in invoice updaters, not take-self-return-Self #1331

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

Merged

Conversation

TheBlueMatt
Copy link
Collaborator

The take-self-return-Self idiom in Rust is substantially less
usable than it is in Java, where its more common. Because we have
to take self by move, it prevents using the update methods to
actually update features, something we occasionally want to do.

See, eg, the change in lightning-invoice where we previously had
to copy and re-create an entire vec of fields just to update the
features field, which is nuts.

There are a few places where this makes things a little less clean,
but the tradeoff to enable more effecient and broader uses of the
update methods seems worth it.

The take-self-return-Self idiom in Rust is substantially less
usable than it is in Java, where its more common. Because we have
to take self by move, it prevents using the update methods to
actually update features, something we occasionally want to do.

See, eg, the change in lightning-invoice where we previously had
to copy and re-create an entire vec of fields just to update the
features field, which is nuts.

There are a few places where this makes things a little less clean,
but the tradeoff to enable more effecient and broader uses of the
update methods seems worth it.
@codecov-commenter
Copy link

Codecov Report

Merging #1331 (b7d57ea) into main (e43cfe1) will increase coverage by 0.10%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1331      +/-   ##
==========================================
+ Coverage   90.52%   90.62%   +0.10%     
==========================================
  Files          72       72              
  Lines       39618    40370     +752     
==========================================
+ Hits        35864    36587     +723     
- Misses       3754     3783      +29     
Impacted Files Coverage Δ
lightning-invoice/src/lib.rs 88.24% <100.00%> (-0.02%) ⬇️
lightning/src/ln/features.rs 98.30% <100.00%> (+0.02%) ⬆️
lightning/src/routing/router.rs 93.07% <100.00%> (+1.15%) ⬆️
lightning/src/ln/functional_tests.rs 97.06% <0.00%> (-0.07%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e43cfe1...b7d57ea. Read the comment docs.

Comment on lines -321 to 328
pub fn $optional_setter(mut self) -> Self {
pub fn $optional_setter(&mut self) {
<T as $feature>::set_optional_bit(&mut self.flags);
self
}

/// Set this feature as required.
pub fn $required_setter(mut self) -> Self {
pub fn $required_setter(&mut self) {
<T as $feature>::set_required_bit(&mut self.flags);
self
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we still support the chained-notation by taking a &mut self and returning &Self?

Copy link
Collaborator Author

@TheBlueMatt TheBlueMatt Feb 24, 2022

Choose a reason for hiding this comment

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

I'd tried that and realized you still have to declare the variable but you're right, you can at least then be able to chain two setters which is nice. That said, its hard to map that in language bindings, cause we don't have first-class support for references in client languages.

Copy link
Contributor

Choose a reason for hiding this comment

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

In addition to the updated mutators, I wonder if we should have a different notation for initialization. Something like:

let features = InvoiceFeatures:from_bits(VariableLengthOnion::required() | PaymentSecret::required());

Would still need to do it in such away that it could be checked at compile time, of course.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yea, that'd be cool, I'd think we'd have to use macros, tho maybe we can override |, as ugly as that is.

Comment on lines -321 to 328
pub fn $optional_setter(mut self) -> Self {
pub fn $optional_setter(&mut self) {
<T as $feature>::set_optional_bit(&mut self.flags);
self
}

/// Set this feature as required.
pub fn $required_setter(mut self) -> Self {
pub fn $required_setter(&mut self) {
<T as $feature>::set_required_bit(&mut self.flags);
self
}
Copy link
Contributor

Choose a reason for hiding this comment

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

In addition to the updated mutators, I wonder if we should have a different notation for initialization. Something like:

let features = InvoiceFeatures:from_bits(VariableLengthOnion::required() | PaymentSecret::required());

Would still need to do it in such away that it could be checked at compile time, of course.

@jkczyz jkczyz merged commit ca163c3 into lightningdevkit:main Mar 11, 2022
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.

4 participants