-
Notifications
You must be signed in to change notification settings - Fork 1
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
Default values for struct fields #1
Comments
Is there a key pain point or points this feature aims to address? I think the use case for it would affect whether its applied implicitely or explicitely. If the goal is to make it possible to add to structs without breaking, then an implicit use makes sense. Wheras if the goal is to just make it possible to build structs more orgonomically then either an implicit or explicit (like Then there's the question raised about named args in fns, and how that could benefit from this. I guess this RFC would just be targetting struct field defaults, with possible consideration for a future one for fns? |
For me, the main motivation is ergonomics. I think that back-compat is also a good motivation, and relies on the modularity improvements this brings (it would mean you could have a publicly instantiable struct with private fields). re named args in fns, the link is really by analogy at this stage - there is an obvious correspondence between fn args and tuples, and between named args and anonymous structs. If structs have deafults for fields, then the analogy extends to default arguments. Since there is no concrete proposal for named or default args at the moment, this is all theoretical, however, I think it is worth thinking about in the design here. |
The big thing I see here is using struct expressions as the public API for intializing a struct instead of builders or constructors. This is flexible (vs constructors) and ergonomic (vs builders) for structs that don't need complicated intialization logic and wish to be future-proof. This would require not only default values for fields but default expressions. Rough discussion on specific points: Syntax? Same as let bindings, Type inference for fields? No, require a type annotation. Otherwise Which values are allowed as defaults? Allowing only constants would narrow the space of types that can take a default value. To make this feature broadly useful the default value should be generalized to a default expression. If a field implements Interaction with .. in initialisers? An initialiser that uses default expressions must end with Interaction with Some overlap with default arguments/keyword arguments? This serves a similar use case but is less general and somewhat orthogonal, restricts the added complexity to struct initialisation. Hopefully also less contentious. Sets precedent regarding syntax for defaults. Big overlap with annonymous structs proposal. Also, is there overlap with fields in traits? If the very rough design described here makes any sense, I'm willing to collaborate in some degree with an RFC. |
Worth thinking about const expressions as an intermediate between values and full expressions. Worth thinking about any similarities and differences between field defaults and consts/statics.
I think that a single default for a field means we can't match builders for expressivity, but compares well with ctors.
This seems worth discussing - there is an explictness argument to be made for requiring types, but global type inference is not required (unlike say function arguments). Rustdoc already uses the compiler, so I don't think having to do type inference will be too problematic.
There is a trade-off here certainly, and it seems worth discussing. Would be good to see examples. Some questions: when would the expression be executed? Does it have inputs? Could the compiler optimise it sometimes? Is there a surpising cost here?
This also depends on what we allow as the expression. It has been brought up elsewhere that we might want special syntax for this, although that is probably only necessary if the expression is not valid.
Again, worth some discussion. There is certainly a trade-off between implicit and explicit. What about using
And is that syntax reasonable? Worth exploring with some examples.
Would we allow defaults there? What would be the meaning? |
I feel like the best way to progress would be to come up with some concrete examples, and deal with edge cases as they arise. @nrc how do you go from discussion that may end up running in circles indefinitely to a concrete proposal that anchors that discussion? |
@KodrAus making some examples sounds like a good way to start - I'd draw some up and check them in to the directory. I hesitate to recommend steps beyond that in terms of design because examples often throw out lots of useful info. I'd also start drafting the motivation. Having a firm idea of the motivation for a feature is a good way to clarify design discussion. |
Gotcha. Well there's lots of feedback around motivations, benefits and drawbacks floating around in the discussion links you've posted, so I'll spend some time this evening pulling that together. |
@KodrAus Could you submit as a PR please? It is easier to give feedback that way. |
I'll explore something between consts and any expression. Consider What if we required that for a But when can we mark a default as reasonable? May it allocate, panic, do I/O? Can this be checked or is it audited? If it is audited, should it be allowed outside of std? Could the definition of
I would find it very surprising if |
There was a suggestion in one of the previous discussions about using a special syntax for I'm interested on this point about discussing the relative merits of default values vs constructors - a ctor function which only takes some fields and has defaults for others is the current way to emulate field defaults. Part of the motivation discussion must be about where one would prefer a ctor function and where one would use default fields. In particular, a ctor allows initialising things like I don't think one can change the definition of |
I started leaning towards pub struct Data {
pub value: bool,
private_stuff: () = {
let client = hyper::Client::new();
let value = client.do_some_http();
value.unwrap();
}
} Which has a few problems (apart from being junky code):
It would make me feel dubious about building structs because I don't know what it could be doing in the background. Limiting values to constant expressions mitigates the weirdness someone could do, which is necessary if this is a feature that requires no special syntax. If it did require special syntax though, then I'd be totally ok with it doing strange things because I've opted in to that behaviour. So I think that's what differentiates value defaults from ctors. You expect a function to do things, and you can use an appropriate type when errors come up, because that type is surfaced to the user. The unfortunate case are those heap collections like @leodasvacas mentions. If not being able to default them makes this feature useless, then maybe it should allow arbitrary expressions, and then use an opt-in syntax. Oh the tradeoffs! |
@nrc For one thing the number of required ctors blows up if you want the flexibility of having all combinations like you have in struct expressions, each field doubles the number of possible ctors. But yes that is an important discussion to add to the motivation.
@KodrAus Agree with your view on the tradeoffs. |
You bring up an important point - it is the fact that default fields are overridable (at least if they're not private) which makes them more powerful than ctor functions.
This might be worth investigating. I'm not sure if it is possible to make it |
So:
Is that state of affairs acceptable? Or is there some alternative implementation (either loosening the Personally, I like the idea of getting more things constable (can we keep that pun in the RFC?), because that benefits more people... But could be impossible or unreasonable for some important types. |
@KodrAus this all sounds good to me. We might also consider some sugar for supporting |
Personally, I'm not opposed to allowing |
Awesome, so, I believe this issue is done (well, not really till the RFC is accepted (or not), but I think there is no more to do here). |
Specify a default value for fields so that they don't need to be given in struct initialisers.
Points to consider:
Default
, can we use that value somehow?derive(Default)
..
in initialisersPrevious discussion
Working directory: default-fields
The text was updated successfully, but these errors were encountered: