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

Correct the partial initialization of a struct #42692

Closed
iddm opened this issue Jun 16, 2017 · 15 comments
Closed

Correct the partial initialization of a struct #42692

iddm opened this issue Jun 16, 2017 · 15 comments

Comments

@iddm
Copy link

iddm commented Jun 16, 2017

Here is a question about the partial initialization of a struct. The answer there says that to use the ..Default::default() syntax your type must implement the Default trait, however, I don't see any reason for this.

Assume we have the following code:

struct A {
    field: u64,
}
struct B {
    field_a: A,
    field_b: Option<bool>,  // Option<bool> implements `Default` trait
    field_c: Option<String>,  // Option<bool> implements `Default` trait
    field_d: bool,    // bool implements `Default` trait
}

So, when we want to partially initialize it we actually don't need a Default trait to be implemented for our struct B, but we do for it's fields which we don't initialize (we initialize them by using Default):

impl B {
    fn new(a: A) {
        B {
            field_a: A,    // We have just specified the field which does not implement `Default` trait
            ..Default::default()    // We have said that everything else is constructed with default values because their types implement Default trait
        }
    }
}

So, there is really no need in Default trait to be implement for the whole structure B if it's fields do that. You simply don't even touch the Default trait of B structure, but you do that for it's fields!

Can we improve partial structs initialization not to require Default trait for the whole type if we don't use it actually?

@TimNN
Copy link
Contributor

TimNN commented Jun 16, 2017

Inferring from your post, I think you are missing a key fact: The B { field_a: A, ..xyz } syntax has nothing to do with Default: It merely states "initialise the explicitly given fields and take the rest from xyz (where xyz is an instance of B)"

So the current syntax always requires a completely constructed object. What is proposed here, initialising missing fields individually by some method, would be an entirely new feature I think (and thus https://github.com/rust-lang/rfcs may be a better place for this issue).

@Mark-Simulacrum
Copy link
Member

Yes, this change would need an RFC. If you'd like to pursue this, please go through the RFC process. You can start by either filing an issue on rust-lang/rfcs or starting a thread on internals.rust-lang.org to discuss this.

@iddm
Copy link
Author

iddm commented Jun 17, 2017

@Mark-Simulacrum, @TimNN okay, I will make an rfc.

@iddm
Copy link
Author

iddm commented Jun 18, 2017

@TimNN Could you point me do the docs which explain current behavior please?

Inferring from your post, I think you are missing a key fact: The B { field_a: A, ..xyz } syntax has nothing to do with Default: It merely states "initialise the explicitly given fields and take the rest from xyz (where xyz is an instance of B)"

@TimNN
Copy link
Contributor

TimNN commented Jun 18, 2017

@vityafx:

See either the second edition of the Book, the first edition of the Book or the Reference.

@iddm
Copy link
Author

iddm commented Jun 18, 2017

@TimNN Thanks! Sorry for asking a question again, could you also point me to the source code where this syntax is parsed? I am working on "Implementation details" part now of the rfc..

@TimNN
Copy link
Contributor

TimNN commented Jun 18, 2017

@vityafx: No problem! The parsing happens here as far as I can tell, although you shouldn't need to look at that code to write the RFC.

@iddm
Copy link
Author

iddm commented Jun 18, 2017

@TimNN yes, I understand that :) I just want to implement the feature by myself and try some variants of it. Thanks a lot for the link!

@steveklabnik
Copy link
Member

I believe @ubsan was recently asking about this as well; maybe they'd be interested in getting involved

@strega-nil
Copy link
Contributor

not me, sorry! The only thing I'm really interested in is allowing Xyz<T> { t, ..xyz } where xyz is an Xyz<U>.

@kahing
Copy link

kahing commented Oct 6, 2018

I workaround this by having a Required type that's an Optional, which implements Deref and DerefMut that unwraps the said Optional. A bit of a hack but works fine.

@rlidwka
Copy link

rlidwka commented Jan 27, 2023

The answer there says that to use the ..Default::default() syntax your type must implement the Default trait, however, I don't see any reason for this.

Default values for a struct may be different from default values of any individual struct member.

#[derive(Debug)]
struct A {
    one: i32,
    two: i32,
    three: i32,
}

impl Default for A {
    fn default() -> Self {
        A {
            one: 1,
            two: 2,
            three: 3,
        }
    }
}

dbg!(A {
    one: 111,
    ..default() // expecting `two: 2`, not `two: 0`
});

Thus, you cannot initialize struct with default values of each struct members, that would be ambiguous and/or break backward compatibility.

@iddm
Copy link
Author

iddm commented Jan 27, 2023

Yes, it is ambiguous and would require breaking backwards compatibility. That's why I am not so sure anymore whether it is good to have it, or we could just live with it.

@m1guelpf
Copy link

@vityafx Did you ever get around to writing an RFC for this?

@iddm
Copy link
Author

iddm commented Aug 20, 2023

@vityafx Did you ever get around to writing an RFC for this?

Can't remember, probably not.

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

No branches or pull requests

8 participants