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

Behavioural changes and Struct Records question for F# RFC FS-1049 #333

Merged
merged 1 commit into from
Sep 15, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 64 additions & 15 deletions RFCs/FS-1049-nested-record-field--copy-and-update-expression.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,79 @@ Enable updating nested record field with "with" syntax.
# Motivation
[motivation]: #motivation

This improves readability. In cases where need to update the value of a nested field in record.
This improves readability in cases where nested record field values need to be updated.

For example, take the following code:

```fsharp
type Street = { N: string }
type Address = { S: Street }
type Person = { A: Address; Age: int }

let person = { A = { S = { N = "Street 1" } }; Age = 30 }

let anotherPerson = { person with A = { person.A with S = { person.A.S with N = person.A.S.N + ", k.2" } } }

let anotherPerson1 = { person with A.S.N = person.A.S.N + ", k.2" }
```

# Detailed design
[design]: #detailed-design

Carefully transform the ast in TypeChecker.fs to expand to the current form
Need to consider in some cases
1. Handle the possible ambiguity of specifing type name vs field name
Transform the AST in TypeChecker.fs to expand the new syntax into the current form.

````fsharp
let anotherPerson = { person with A.S.N = person.A.S.N + ", k.2" }
````

Becomes:

````fsharp
let anotherPerson = { person with A = { person.A with S = { person.A.S with N = person.A.S.N + ", k.2" } } }
````

Need to consider:

1. Handle the possible ambiguity of specifying type name vs field name
2. Group nested field from the same parent
3. All nested field parts need to be decleard on record type
3. All nested field parts need to be declared on record type
4. Collaborate with anonymous records feature
5. Check IntelliSense
6. Investigate other language features that should support nested paths like named arguments
7. Check no same nested field update
7. Check same field is not updated twice within statement

## Syntax

This change allows updating nested fields, using dot notation, within one copy and update statement.

````fsharp
let anotherPerson = { person with A.S.N = "1" }
````

Multiple fields with differing levels of nesting can be updated within the same expersssion.

````fsharp
let anotherPerson = { person with A.S.N = "1"; Age = 1; }
````

Fields can be accessed through Namespace, Module or Type name.

The implementation expands the nested syntax into the existing AST for nested updates so qualified access is checked through the same mechanism.

__TypeName Access__
````fsharp
let anotherPerson = { Person.A.S.N = "1"; Person.Age = 1; }
````

__ModuleOrNamespaceName Access__
````fsharp
let anotherPerson = { ModuleOrNamespaceName.A.S.N = "1"}
````

__ModuleOrNamespaceName.TypeName Access__
````fsharp
let anotherPerson = { ModuleOrNamespaceName.Person.A.S.N = "1" }
````

# Drawbacks
[drawbacks]: #drawbacks
Expand All @@ -56,34 +101,38 @@ Additional complexity in the compiler.

This is not a breaking change, and is backwards-compatible with existing code.

# Open Questoions
# Open Questions

Q: What about indexers, e.g.
```
```fsharp
let anotherPerson1 = { person with A.[3].N = person.A.[3].N + ", k.2" }
```
A:Need to look at it
A: Need to look at it

Q: What happens to cases where A.S is mentioned twice?

```
```fsharp
{ person with A.S.N = person.A.S.N + ", k.2"; A.S.M = person.A.S.M + ", k.3" }
```

A: Already implemented will compile to

```
```fsharp
{ person with A = { person.A with S = { person.A.S with N = person.A.S.N + ", k.2"; M = person.A.S.M + ", k.3" }
```

Q: What about similar features in the language that name fields, especially mutating property setters

```
```fsharp
Person(A.C.N = 3, A.C.M = 4)
```

A: Need to look at it after we finish with the records

Q: [_Will it work with struct records without introducing lot's of struct copy?_](https://github.com/Microsoft/visualfsharp/pull/4511#issuecomment-401640471)

A: The current implementation is expanding the simplified AST into the existing one and will have the same struct copy issue mentioned by @zpodlovics. However, as this issue is present in the original copy and update expression this would have to be fixed as well as updating the new implementation. This will be investigated further once the open tasks are completed.

# Alternatives

- Do not implement this feature