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

Clone docs say it can't be derived for function pointers but it can #73480

Closed
martin-t opened this issue Jun 18, 2020 · 3 comments · Fixed by #114029
Closed

Clone docs say it can't be derived for function pointers but it can #73480

martin-t opened this issue Jun 18, 2020 · 3 comments · Fixed by #114029
Labels
A-docs Area: documentation for any part of the project, including the compiler, standard library, and tools C-bug Category: This is a bug.

Comments

@martin-t
Copy link

The text is here:

An example is a generic struct holding a function pointer. In this case, the implementation of Clone cannot be derived, but can be implemented as:

...

However, it's in fact possible to derive:

#[derive(Clone)]
struct Generate<T>(fn() -> T);

(playground)

@jonas-schievink jonas-schievink added C-bug Category: This is a bug. A-docs Area: documentation for any part of the project, including the compiler, standard library, and tools labels Jun 18, 2020
@ratijas
Copy link
Contributor

ratijas commented Jun 18, 2020

The wording is incorrect, but the idea is the same: derived implementation will be restricted to T: Clone which is not what you'd want when cloning a function pointer to a function which returns T.

Consider this:

#![allow(unused)]

#[derive(Clone)]
struct Generate<T>(fn() -> T);

struct NonClone();

fn non_clone() -> NonClone {
    NonClone()
}

#[derive(Clone)]
struct CanClone();

fn can_clone() -> CanClone {
    CanClone()
}

fn main() {
    let g = Generate(non_clone);
    // g.clone(); // compile error!

    let g = Generate(can_clone);
    g.clone();
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c1d1fbcd7e5f09df91378731bdbcf0ff

Basically, generated implementation looks like this:

impl<T> Clone for Generate<T>
    where T: Clone
{
    fn clone(&self) -> Self {...}
}

But you'd want it to be simpler, like in the doc:

impl<T> Clone for Generate<T> {
    fn clone(&self) -> Self {
        *self
    }
}

And that's exactly what I did myself here: https://github.com/ratijas/qmetaobject-rs/blob/72b349b65dad3135fcc344d2268c3a453e0ac844/qmetaobject/src/connections.rs#L65-L72


Nice profile picture, btw.

@cuviper
Copy link
Member

cuviper commented Jun 18, 2020

See #26925 for a long debate about that derived behavior.

@martin-t
Copy link
Author

Oh, i see what's happening here. There is another weird phrasing in the Copy docs which confused me:

There is a small difference between the two: the derive strategy will also place a Copy bound on type parameters, which isn't always desired.

I interpreted "place Copy bounds" as putting an invisible T: Copy on the struct definition itself, instead of just on the impl:

#[derive(Clone, Copy)]
struct Derived<T>(T);

#[derive(Clone)]
struct BoundOnStruct<T: Copy>(T);
impl<T: Copy> Copy for BoundOnStruct<T> {}

#[derive(Clone)]
struct BoundOnImpl<T>(T);
impl<T: Copy> Copy for BoundOnImpl<T> {}

I thought Derived was equivalent to BoundOnStruct but it's actually like BoundOnImpl. I should have probably known better at this point but at least i am not the only one mislead by it - maybe that should be rephrased too?

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 5, 2023
Explain more clearly why `fn() -> T` can't be `#[derive(Clone)]`

Closes rust-lang#73480

The derived impls were generated with `rustc -Z unpretty=expanded main.rs` and the raw output is:

```rust
struct Generate<T>(fn() -> T);
#[automatically_derived]
impl<T: ::core::marker::Copy> ::core::marker::Copy for Generate<T> { }
#[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for Generate<T> {
    #[inline]
    fn clone(&self) -> Generate<T> {
        Generate(::core::clone::Clone::clone(&self.0))
    }
}
```
@bors bors closed this as completed in bedadff Aug 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-docs Area: documentation for any part of the project, including the compiler, standard library, and tools C-bug Category: This is a bug.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants