-
Notifications
You must be signed in to change notification settings - Fork 12
/
lifetimes.d
341 lines (255 loc) · 12.1 KB
/
lifetimes.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
Ddoc
$(DERS_BOLUMU $(IX lifetime) Lifetimes and Fundamental Operations)
$(P
We will soon cover structs, the basic feature that allows the programmer to define application-specific types. Structs are for combining fundamental types and other structs together to define higher-level types that behave according to special needs of programs. After structs, we will learn about classes, which are the basis of the object oriented programming features of D.
)
$(P
Before getting to structs and classes, it will be better to talk about some important concepts first. These concepts will help understand structs and classes and some of their differences.
)
$(P
We have been calling any piece of data that represented a concept in a program a $(I variable). In a few places we have called struct and class variables specifically as $(I objects). I will continue calling both of these concepts variables in this chapter.
)
$(P
Although this chapter includes only fundamental types, slices, and associative arrays; these concepts apply to user-defined types as well.
)
$(H5 $(IX variable, lifetime) Lifetime of a variable)
$(P
The time between when a variable is defined and when it is $(I finalized) is the lifetime of that variable. Although it is the case for many types, $(I becoming unavailable) and $(I being finalized) need not be at the same time.
)
$(P
You would remember from the $(LINK2 /ders/d.en/name_space.html, Name Scope chapter) how variables become unavailable. In simple cases, exiting the scope where a variable has been defined would make that variable unavailable.
)
$(P
Let's consider the following example as a reminder:
)
---
void speedTest() {
int speed; // Single variable ...
foreach (i; 0 .. 10) {
speed = 100 + i; // ... takes 10 different values.
// ...
}
} // ← 'speed' is unavailable beyond this point.
---
$(P
The lifetime of the $(C speed) variable in that code ends upon exiting the $(C speedTest()) function. There is a single variable in the code above, which takes ten different values from 100 to 109.
)
$(P
When it comes to variable lifetimes, the following code is very different compared to the previous one:
)
---
void speedTest() {
foreach (i; 0 .. 10) {
int speed = 100 + i; // Ten separate variables.
// ...
} // ← Lifetime of each variable ends here.
}
---
$(P
There are ten separate variables in that code, each taking a single value. Upon every iteration of the loop, a new variable starts its life, which eventually ends at the end of each iteration.
)
$(H5 $(IX parameter, lifetime) Lifetime of a parameter)
$(P
The lifetime of a parameter depends on its qualifiers:
)
$(P
$(IX ref, parameter lifetime) $(C ref): The parameter is just an alias of the actual variable that is specified when calling the function. $(C ref) parameters do not affect the lifetimes of actual variables.
)
$(P
$(IX in, parameter lifetime) $(C in): For $(I value types), the lifetime of the parameter starts upon entering the function and ends upon exiting it. For $(I reference types), the lifetime of the parameter is the same as with $(C ref).
)
$(P
$(IX out, parameter lifetime) $(C out): Same with $(C ref), the parameter is just an alias of the actual variable that is specified when calling the function. The only difference is that the variable is set to its $(C .init) value automatically upon entering the function.
)
$(P
$(IX lazy, parameter lifetime) $(C lazy): The life of the parameter starts when the parameter is actually used and ends right then.
)
$(P
The following example uses these four types of parameters and explains their lifetimes in program comments:
)
---
void main() {
int main_in; /* The value of main_in is copied to the
* parameter. */
int main_ref; /* main_ref is passed to the function as
* itself. */
int main_out; /* main_out is passed to the function as
* itself. Its value is set to int.init
* upon entering the function. */
foo(main_in, main_ref, main_out, aCalculation());
}
void foo(
in int p_in, /* The lifetime of p_in starts upon
* entering the function and ends upon
* exiting the function. */
ref int p_ref, /* p_ref is an alias of main_ref. */
out int p_out, /* p_out is an alias of main_out. Its
* value is set to int.init upon
* entering the function. */
lazy int p_lazy) { /* The lifetime of p_lazy starts when
* it is used and ends when its use
* ends. Its value is calculated by
* calling aCalculation() every time
* p_lazy is used in the function. */
// ...
}
int aCalculation() {
int result;
// ...
return result;
}
---
$(H5 Fundamental operations)
$(P
Regardless of its type, there are three fundamental operations throughout the lifetime of a variable:
)
$(UL
$(LI $(B Initialization): The start of its life.)
$(LI $(B Finalization): The end of its life.)
$(LI $(B Assignment): Changing its value as a whole.)
)
$(P
To be considered an object, it must first be initialized. There may be final operations for some types. The value of a variable may change during its lifetime.
)
$(H6 $(IX initialization) Initialization)
$(P
Every variable must be initialized before being used. Initialization involves two steps:
)
$(OL
$(LI $(B Reserving space for the variable): This space is where the value of the variable is stored in memory.)
$(LI $(B Construction): Setting the first value of the variable on that space (or the first values of the members of structs and classes).)
)
$(P
Every variable lives in a place in memory that is reserved for it. Some of the code that the compiler generates is about reserving space for each variable.
)
$(P
Let's consider the following variable:
)
---
int speed = 123;
---
$(P
As we have seen in $(LINK2 /ders/d.en/value_vs_reference.html, the Value Types and Reference Types chapter), we can imagine this variable living on some part of the memory:
)
$(MONO
──┬─────┬─────┬─────┬──
│ │ 123 │ │
──┴─────┴─────┴─────┴──
)
$(P
The memory location that a variable is placed at is called its address. In a sense, the variable lives at that address. When the value of a variable is changed, the new value is stored at the same place:
)
---
++speed;
---
$(P
The new value would be at the same place where the old value has been:
)
$(MONO
──┬─────┬─────┬─────┬──
│ │ 124 │ │
──┴─────┴─────┴─────┴──
)
$(P
Construction is necessary to prepare variables for use. Since a variable cannot be used reliably before being constructed, it is performed by the compiler automatically.
)
$(P
Variables can be constructed in three ways:
)
$(UL
$(LI $(B By their default value): when the programmer does not specify a value explicitly)
$(LI $(B By copying): when the variable is constructed as a copy of another variable of the same type)
$(LI $(B By a specific value): when the programmer specifies a value explicitly)
)
$(P
When a value is not specified, the value of the variable would be the $(I default) value of its type, i.e. its $(C .init) value.
)
---
int speed;
---
$(P
The value of $(C speed) above is $(C int.init), which happens to be zero. Naturally, a variable that is constructed by its default value may have other values during its lifetime (unless it is $(C immutable)).
)
---
File file;
---
$(P
With the definition above, the variable $(C file) is a $(C File) object that is not yet associated with an actual file on the file system. It is not usable until it is modified to be associated with a file.
)
$(P
Variables are sometimes constructed as a copy of another variable:
)
---
int speed = otherSpeed;
---
$(P
$(C speed) above is constructed by the value of $(C otherSpeed).
)
$(P
As we will see in later chapters, this operation has a different meaning for class variables:
)
---
auto classVariable = otherClassVariable;
---
$(P
Although $(C classVariable) starts its life as a copy of $(C otherClassVariable), there is a fundamental difference with classes: Although $(C speed) and $(C otherSpeed) are distinct values, $(C classVariable) and $(C otherClassVariable) both provide access to the same value. This is the fundamental difference between value types and reference types.
)
$(P
Finally, variables can be constructed by the value of an expression of a compatible type:
)
---
int speed = someCalculation();
---
$(P
$(C speed) above would be constructed by the return value of $(C someCalculation()).
)
$(H6 $(IX finalization) $(IX destruction) Finalization)
$(P
Finalizing is the final operations that are executed for a variable and reclaiming its memory:
)
$(OL
$(LI $(B Destruction): The final operations that must be executed for the variable.)
$(LI $(B Reclaiming the variable's memory): Reclaiming the piece of memory that the variable has been living on.)
)
$(P
For simple fundamental types, there are no final operations to execute. For example, the value of a variable of type $(C int) is not set back to zero. For such variables there is only reclaiming their memory, so that it will be used for other variables later.
)
$(P
On the other hand, some types of variables require special operations during finalization. For example, a $(C File) object would need to write the characters that are still in its output buffer to disk and notify the file system that it no longer uses the file. These operations are the destruction of a $(C File) object.
)
$(P
Final operations of arrays are at a little higher-level: Before finalizing the array, first its elements are destructed. If the elements are of a simple fundamental type like $(C int), then there are no special final operations for them. If the elements are of a struct or a class type that needs finalization, then those operations are executed for each element.
)
$(P
Associative arrays are similar to arrays. Additionally, the keys may also be finalized if they are of a type that needs destruction.
)
$(P $(B The garbage collector:) D is a $(I garbage-collected) language. In such languages finalizing an object need not be initiated explicitly by the programmer. When a variable's lifetime ends, its finalization is automatically handled by the garbage collector. We will cover the garbage collector and special memory management in $(LINK2 /ders/d.en/memory.html, a later chapter).
)
$(P
Variables can be finalized in two ways:
)
$(UL
$(LI $(B When the lifetime ends): The finalization happens upon the end of life of the variable.)
$(LI $(B Some time in the future): The finalization happens at an indeterminate time in the future by the garbage collector.)
)
$(P
Which of the two ways a variable will be finalized depends primarily on its type. Some types like arrays, associative arrays and classes are normally destructed by the garbage collector some time in the future.
)
$(H6 $(IX assignment) Assignment)
$(P
The other fundamental operation that a variable experiences during its lifetime is assignment.
)
$(P
For simple fundamental types assignment is merely changing the value of the variable. As we have seen above on the memory representation, an $(C int) variable would start having the value 124 instead of 123. However, more generally, assignment consists of two steps, which are not necessarily executed in the following order:
)
$(UL
$(LI $(B Destructing the old value))
$(LI $(B Constructing the new value))
)
$(P
These two steps are not important for simple fundamental types that don't need destruction. For types that need destruction, it is important to remember that assignment is a combination of the two steps above.
)
Macros:
SUBTITLE=Lifetimes and Fundamental Operations
DESCRIPTION=Introducing the concepts of initialization, finalization, construction, destruction, and assignment and defining the lifetimes of variables.
KEYWORDS=d programming lesson book tutorial constructor destructor