I remember discussing this a while ago. I thought I had an issue open somewhere for this but I guess not.
It's currently not allowed to use FRU (functional record update) syntax to return a transformed type, i.e.:
struct Foo<T> {
val: T,
tag: &'static str,
}
impl<T> Foo<T> {
fn transform<U>(self, val: U) -> Foo<U> {
Foo { val: val, .. self }
}
}
will throw a "mismatched type" error with the span of self in the FRU literal because it is of type Foo<T> and not Foo<U>, even though the remaining fields of self are compatible.
According to RFC 736, FRU is supposed to be just syntactic sugar for a full struct literal, but a full struct literal works in this case because it doesn't place any restriction on the type of self.
Possible solutions:
Move fields nominally (foo: <tail expr>.foo, bar: <tail expr>.bar, etc.) and typecheck them individually, not typechecking the tail expression at all. This could allow FRU to work even between otherwise incompatible types which have compatible fields. I like this one more but it may be too implicit for some, and I gather that we don't want to add too much meaning to field names.
Only check equality of the outermost type constructor between the FRU literal and the tail expression, i.e. check that Foo<T> ~= Foo<U>; then, typecheck the moved fields individually. This would allow the above use-case but disallow using an entirely different type as the source or destination.
As far as I understand it, this should be backwards-compatible since it would strictly allow more code to compile.
Edit: clarify generic params
Sorry if this is a silly question, but what are the precise difference between Foo<T>, Foo<T_> and Foo<_>?
@mark-i-m, in this case T_ is just another type parameter. It's not the same as T, it could also be called K or NotT or anything else. The _ on its own means the type parameter is inferred, so we don't give it an explicit name in our code, but it's still there. I usually read Foo<_> as _Foo of Whatever_.
@KodrAus Got it :smile: I wasn't sure if T_ was some sort semi-inferred generic or something... Thanks!
Does anyone plan to write an RFC on this?
I can, but it'd be basically just the OP here.
Also, not sure on which of the hypothesized solutions is better, that would have to be fleshed out before an RFC draft wouldn't it?
@abonander I'd go with the more conservative route, i.e. matching fields not by name but rather by the fact that they're defined in the same struct.
We might want structural records back eventually, so avoid messing them up if possible.
Based on the last comment on that thread and the fact that the compiler now does rearrange fields, structural records probably won't be making a return. If they do, it seems to be a completely orthogonal feature.
I doubt the compiler rearranging fields poses any serious concern, but sure the syntax do not obviously conflict since Foo { .. } is quite different from { .. } or whatever.
I put together a draft of an RFC for this. The trickiest part was thinking through the implications for type inference.
Does anyone have thoughts before I submit a PR? I haven't written an RFC before. In particular, I'm unsure if some of my terminology is correct/understandable, if the type inference sections make sense, and if I've provided sufficient detail. Also, am I missing any obvious edge cases?
@jturner314 At a glance it looks okay to me, though I don't care so much about the details as long as something gets implemented. 😄
You can try posting it to internals.rust-lang.org for early comments but the RFC process itself is supposed to be the actual avenue for developing a proposal. Any issues should get shaken out at that point.
@jturner314 My initial reading is that this is a solidly written and well thought out RFC; Nice work, especially as your first RFC. I left some notes that are nits.
@jturner314 Looks great, please do open a PR!
cc @nikomatsakis
I've submitted PR #2528. I made some changes from my initial version (primarily wording and more examples). Thanks for everyone's comments!
Closing in favor of https://github.com/rust-lang/rfcs/pull/2528.
Most helpful comment
I put together a draft of an RFC for this. The trickiest part was thinking through the implications for type inference.
Does anyone have thoughts before I submit a PR? I haven't written an RFC before. In particular, I'm unsure if some of my terminology is correct/understandable, if the type inference sections make sense, and if I've provided sufficient detail. Also, am I missing any obvious edge cases?