Skip to content
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

Consider taking writers by value #20

Open
HadrienG2 opened this issue Sep 6, 2019 · 8 comments · May be fixed by #26
Open

Consider taking writers by value #20

HadrienG2 opened this issue Sep 6, 2019 · 8 comments · May be fixed by #26

Comments

@HadrienG2
Copy link

&mut T where T: Write implements Write, so there is no reason to ask for a borrowed writer in the API. But this is unlikely to be a problem in practice because owned writers are rarely used.

@HadrienG2 HadrienG2 changed the title Consider taking the writer by value Consider taking writers by value Sep 6, 2019
@frankmcsherry
Copy link
Member

This seems very plausible! I'll check it out.

@frankmcsherry
Copy link
Member

Investigation suggests that while this is fine for encode, it could be a bit gross for the internals. The reason being if we accept a mut write: W and need to use it multiple times, we would need to invoke recursive calls with &mut write to avoid transferring ownership. This results in a recursive call with the write implementor &mut W, and each bit of structural recursion layers on a new &mut.

This seems like it would confound structural recursion through tree-structured data, e.g.

struct Tree {
    children: Vec<Tree>,
}

@HadrienG2
Copy link
Author

Let's not do this then, as I said it's not a big issue ;)

@HadrienG2
Copy link
Author

HadrienG2 commented Sep 6, 2019

Wait. Given that &mut W implements Write since W implements Write, what prevents you from sending around an &mut writer while traversing a tree ?

@frankmcsherry
Copy link
Member

I think that is what happens now, isn't it? We could allow encode to take a mut writer: W but we probably (?) want entomb to continue to take a writer: &mut W. Maybe I mis-understand what you are proposing though.

@HadrienG2
Copy link
Author

HadrienG2 commented Sep 6, 2019

To clarify, I meant that because &mut W implements Write just like owned writers, this code is legal:

pub fn takes_write_impl(_: impl Write) {}

pub fn also_takes_write_impl(mut w: impl Write) {
    takes_write_impl(&mut w);
    takes_write_impl(w);
}

Therefore, there is no problem with accepting "owned" writers, and using them multiple times.

@frankmcsherry
Copy link
Member

frankmcsherry commented Sep 6, 2019

Yup, I agree. However,

pub fn takes_write_impl(mut w: impl std::io::Write) {
    takes_write_impl(&mut w)
}

fn main() {
    let mut bytes = Vec::new();
    takes_write_impl(&mut bytes);
}

trips a recursion limit

error: reached the recursion limit while instantiating `takes_write_impl::<&mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut &mut std::vec::Vec<u8>>`
 --> src/main.rs:1:1
  |
1 | / pub fn takes_write_impl(mut w: impl std::io::Write) {
2 | |     takes_write_impl(&mut w)
3 | | }
  | |_^

error: aborting due to previous error

This is the problem I think exists, as we seem to need to use &mut writer in the body of many of the writing methods (edit: which may recursively call themselves)

@HadrienG2
Copy link
Author

HadrienG2 commented Sep 6, 2019

Oh, I see. This could cause problems with deep object trees indeed, especially as it also implies that the compiler is generating O(N) copies of take_write_impl when using this pattern, which is a compilation time liability.

Then I agree with you: encode can take a writer by value, but entomb shouldn't.

@HadrienG2 HadrienG2 reopened this Sep 6, 2019
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 a pull request may close this issue.

2 participants