-
Notifications
You must be signed in to change notification settings - Fork 831
[WIP] Nested Record Field Copy and Update Expression #4511
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
[WIP] Nested Record Field Copy and Update Expression #4511
Conversation
…currently not set in SynExpr.Record
…person.A with Address.S = { person.A.S with Street.N = person.A.S.N + ", k.2" } } }
Still need to get it to work for { person with Person.A.S.N = ... }
|
|
|
This pr is working on first class lens I'm working with @williamtetlow as part of FSSF mentorship program We already able to compile code like The current situation "with" syntax able to update 1 level of fields of record We added the ability to update more then 1 level like The way we did it is by transform the ast in the type checker see the example above This is still work in progress We will be happy to get feedback |
|
something that also needs to be done (later when dust settles): for the standard case we have suggestions working. we should add that as well for nested records |
|
Modified the title to be WIP. @williamtetlow and @AviAvni absolutely love seeing this. Can you add a checklist of TODOs to the initial text of this PR so that we can easily see what's left to cover? Thanks! |
|
@cartermp @williamtetlow @AviAvni We also need an RFC for this, and a language suggestion (I couldn't find one on q quick search though one may exist) I have some concerns, in particular about whether nested paths should be supported in other places, e.g. named argument setters: It feels to me like if we're going to support one kind of nested update, we should support two. And what about indexers? This seems useful and orthogonal in the context of both immutable and mutable data. Anyway, I'd like to discuss this properly from a design perspective, to make sure we are not just adding a feature that only applies to records when it can logically apply elsewhere too |
|
@dsyme suggestion fsharp/fslang-suggestions#379 |
|
@dsyme didn't understand to what will compile to |
let temp = obj.Method()
temp.Prop1.NestedProp <- 3This is mostly used in constructors the same way C# has initializer syntax, but in F# it also works on plain methods, applying the setters on the return value. |
|
@AviAvni Currently obj.Method(SettableProp1=x) compiles to let tmp = obj.Method()
tmp.SettableProp1 <- x
tmpSo obj.Method(Prop1.SettableNestedProp1=x)would be let tmp = obj.Method()
tmp.Prop1.SettableNestedProp1 <- x
tmpLikewise there would a question about whether long paths could be used in named and/or optional arguments, e.g. would this have any meaning: member __.Method1(arg1 : SomeType)
obj.Method(arg1.Prop1=x)Though it's not clear what the meaning should be - it's like we would want functional update on a default argument but that doesn't fit that well with how F# does default arguments today. I can see some use for this when option/argument spaces are very large (e.g. charting), e.g. Chart.Plot(Colors.Background=Color.Red, Colors.Foreground=Color.Blue, Layout.Packing=4)The overall point is that we want to maintain some degree of orthogonality (or at least the feeling of orthogonality) between record labels and named arguments... |
|
@dsyme thanks we will work on it after finish with record things |
|
Note also we will need the same thing to work for anonymous records.. #4499. I just did the copy-and-update implementation for that today |
|
@dsyme How should we handle the case of nested access to a record field that is a type with the Should we require the inclusion of the type/module that has been marked as required or allow nested access without this? ( e.g. |
No. The fact the field has type |
…dd Module/Namespace.Module...TypeName.FieldName
added Module/Namespace.TypeName.FieldName resolution
Refactoring Long Ident Resolution into NameResolution module
|
Will it work with struct records without introducing lot's of struct copy? eg.: a 6 level deep nested field access could create lot's of struct copy to access a simple field. Also the update order may matters a lot for struct records. |
|
@williamtetlow Fantastic progress so far, good work. Could you also go through the RFC and update it with the behavioral changes you've made in this PR? Moving forward, we want the RFCs to be a canonical source for what, why, and a high-level how for all future changes to the language. This traceability is crucial for helping people understand behavior and help others on places such as StackOverflow. Additionally, @zpodlovics has a good concern regarding struct records. Could this also be evaluated and written up in the RFC as something that is being accounted for? Thank you! |
|
Right now the struct wrapper ctors are not optimized (https://github.com/dotnet/coreclr/issues/18542) and will require lot's of stack space and copy, especially with deep nesting: https://github.com/dotnet/coreclr/issues/18542#issuecomment-399535658 |
|
RFC has been updated with behavioural changes and answer to @zpodlovics question about struct records. fsharp/fslang-design#333
|
…into nested-recd-update-recdexpr # Conflicts: # src/fsharp/TypeChecker.fs
|
Good job with this @williamtetlow 👍 After the whole SRTP topic is finished I want to help out 😃 |
|
ping |
|
@williamtetlow @AviAvni Any progress on the remaining WIP items? We'll refrain from reviewing until you feel it's ready. Now that Anonymous Records are merged and (soon) shipping, we'll want to make sure this can work with them too. I can update the RFC for that. |
|
Are record fields with union types somehow supported? Like this: type Response = {
printHint: PrintHint option
}
and PrintHint = {
requestPrintHint: RequestPrintHint option;
}
and RequestPrintHint = {
printHeader: bool
}Would it be possible to match cases in a given path of an update Expression and only update on match? |
src/fsharp/NameResolution.fs
Outdated
|
|
||
| let lookup() = | ||
| let frefs = | ||
| try Map.find id.idText nenv.eFieldLabels |> success |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not Map.tryFind with match?
src/fsharp/TypeChecker.fs
Outdated
| //------------------------------------------------------------------------- | ||
|
|
||
| and TcRecdExpr cenv overallTy env tpenv (inherits, optOrigExpr, flds, mWholeExpr) = | ||
| let buildForNestdFlds (lidwd : LongIdentWithDots) v = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think throwing a couple of chars saves a lot of space in this case. Why not buildForNestedFields?
|
@cartermp there hasn't been any progress over the last few months, the intellisense issues are still outstanding and integration with anonymous records. I was struggling to find a solution for the wrong suggestions being presented when you start going more than one field deep. e.g. let anotherPerson1 = { person with A.S.suggests I will catch up with @AviAvni. @vasily-kirichenko thanks for the feedback. I will take a look. |
|
Would be nice if we can get going here again. If I find time to do something again, I want to do something here too. |
d56fc77 to
a5c0b09
Compare
|
@realvictorprm, it's been a long time since anyone looked at this? do you want to take it over or should I close it? Thanks Kevin |
|
I forgot about that thingy. I think this can be considered as long hanging fruit with it being already quite reachable because of the existing progress. I can't promise anything but I'll try to find some time this year to look into it and try to update it and get it working even more. |
|
@realvictorprm, I am going to close this as an orphaned PR. please make a branch in your fork if you want to revisit this PR. We would welcome a PR, when you have something ready for us to work with. Thanks everyone for your attention to this contribution. Kevin |

fsharp/fslang-suggestions#379
TODOs
[<RequireQualifiedAccess>]attribute