You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
add info about accessibility modifiers in constructors for F# records (#49028)
* add info for constructor accessibility modifiers
* make changes from feedback
* remove unnecessary semicolon
* minor fixes
* Update docs/fsharp/language-reference/records.md
---------
Co-authored-by: Bill Wagner <[email protected]>
Copy file name to clipboardExpand all lines: docs/fsharp/language-reference/records.md
+74-28Lines changed: 74 additions & 28 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,19 +6,23 @@ ms.date: 12/21/2021
6
6
---
7
7
# Records (F#)
8
8
9
-
Records represent simple aggregates of named values, optionally with members. They can either be structs or reference types. They are reference types by default.
9
+
Records represent simple aggregates of named values, optionally with members. They can either be structs or reference types. They are reference types by default.
10
10
11
11
## Syntax
12
12
13
13
```fsharp
14
14
[ attributes ]
15
15
type [accessibility-modifier] typename =
16
-
{ [ mutable ] label1 : type1;
17
-
[ mutable ] label2 : type2;
18
-
... }
16
+
[accessibility-modifier] {
17
+
[ mutable ] label1 : type1;
18
+
[ mutable ] label2 : type2;
19
+
...
20
+
}
19
21
[ member-list ]
20
22
```
21
23
24
+
The `accessibility modifier` before the `typename` affects the visibility of the entire type, and is `public` by default. The second `accessibility modifier` only affects the constructor and fields.
25
+
22
26
## Remarks
23
27
24
28
In the previous syntax, *typename* is the name of the record type, *label1* and *label2* are names of values, referred to as *labels*, and *type1* and *type2* are the types of these values. *member-list* is the optional list of members for the type. You can use the `[<Struct>]` attribute to create a struct record rather than a record which is a reference type.
@@ -96,33 +100,33 @@ For example, the following code defines a `Person` and `Address` type as mutuall
96
100
```fsharp
97
101
// Create a Person type and use the Address type that is not defined
98
102
type Person =
99
-
{ Name: string
100
-
Age: int
101
-
Address: Address }
103
+
{ Name: string
104
+
Age: int
105
+
Address: Address }
102
106
// Define the Address type which is used in the Person record
103
107
and Address =
104
-
{ Line1: string
105
-
Line2: string
106
-
PostCode: string
107
-
Occupant: Person }
108
+
{ Line1: string
109
+
Line2: string
110
+
PostCode: string
111
+
Occupant: Person }
108
112
```
109
113
110
114
To create instances of both, you do the following:
111
115
112
116
```fsharp
113
117
// Create a Person type and use the Address type that is not defined
114
118
let rec person =
115
-
{
116
-
Name = "Person name"
117
-
Age = 12
118
-
Address =
119
-
{
120
-
Line1 = "line 1"
121
-
Line2 = "line 2"
122
-
PostCode = "abc123"
123
-
Occupant = person
124
-
}
125
-
}
119
+
{
120
+
Name = "Person name"
121
+
Age = 12
122
+
Address =
123
+
{
124
+
Line1 = "line 1"
125
+
Line2 = "line 2"
126
+
PostCode = "abc123"
127
+
Occupant = person
128
+
}
129
+
}
126
130
```
127
131
128
132
If you were to define the previous example without the `and` keyword, then it would not compile. The `and` keyword is required for mutually recursive definitions.
@@ -147,9 +151,9 @@ You can specify members on records much like you can with classes. There is no s
147
151
148
152
```fsharp
149
153
type Person =
150
-
{ Name: string
151
-
Age: int
152
-
Address: string }
154
+
{ Name: string
155
+
Age: int
156
+
Address: string }
153
157
154
158
static member Default =
155
159
{ Name = "Phillip"
@@ -163,9 +167,9 @@ If you use a self identifier, that identifier refers to the instance of the reco
163
167
164
168
```fsharp
165
169
type Person =
166
-
{ Name: string
167
-
Age: int
168
-
Address: string }
170
+
{ Name: string
171
+
Age: int
172
+
Address: string }
169
173
170
174
member this.WeirdToString() =
171
175
this.Name + this.Address + string this.Age
@@ -174,6 +178,48 @@ let p = { Name = "a"; Age = 12; Address = "abc123" }
174
178
let weirdString = p.WeirdToString()
175
179
```
176
180
181
+
## Accessibility Modifiers on Records
182
+
183
+
The following code illustrates the use of accessibility modifiers. There are three files in the project: `Module1.fs`, `Test1.fs`, and `Test2.fs`. An internal record type and a record type with a private constructor are defined in Module1.
184
+
185
+
```fsharp
186
+
// Module1.fs
187
+
188
+
module Module1
189
+
190
+
type internal internalRecd = { X: int }
191
+
192
+
type recdWithInternalCtor = private { Y: int }
193
+
```
194
+
195
+
In the `Test1.fs` file, the internal record must be initialized with the `internal` access modifier, that's because the protection level of the value and the record must match, and both must belong to the same assembly.
196
+
197
+
```fsharp
198
+
// Test1.fs
199
+
200
+
module Test1
201
+
202
+
open Module1
203
+
204
+
let myInternalRecd1 = { X = 2 } // This line will cause a compiler error.
205
+
206
+
let internal myInternalRecd2 = { X = 4 } // This is OK
207
+
```
208
+
209
+
In the `Test2.fs` file, the record with the private constructor cannot be initialized directly due the protection level of the constructor.
210
+
211
+
```fsharp
212
+
// Test2.fs
213
+
214
+
module Test2
215
+
216
+
open Module1
217
+
218
+
let myRecdWithInternalCtor = { Y = 6 } // This line will cause a compiler error.
219
+
```
220
+
221
+
For more information about accessibility modifiers, see the [Access Control](./access-control.md) article.
222
+
177
223
## Differences Between Records and Classes
178
224
179
225
Record fields differ from class fields in that they are automatically exposed as properties, and they are used in the creation and copying of records. Record construction also differs from class construction. In a record type, you cannot define a constructor. Instead, the construction syntax described in this topic applies. Classes have no direct relationship between constructor parameters, fields, and properties.
0 commit comments