root/trunk/docsrc/final-const-invariant.dd

Revision 659, 10.7 kB (checked in by andrei, 10 months ago)

Changed ddoc extensions to dd and changed linux.mak accordingly

  • Property svn:eol-style set to native
Line 
1 Ddoc
2
3 $(SPEC_S Final$(COMMA) Const$(COMMA) and Invariant,
4
5     $(P
6     Being able to specify what parts of variables data can change, and under
7     what conditions, can add greatly to the understandability of interfaces,
8     being able to analyse code for correctness, and improve code
9     generation.
10     )
11
12     $(P
13     With invariant, const and final, the programmer can carefully control
14     these attributes.
15     )
16
17 <h2>Invariant Storage Class</h2>
18
19     $(P
20     An invariant declaration cannot change, ever, and any data
21     that can be referenced through the invariant cannot ever
22     change. Initializers for invariant declarations can be placed into
23     ROM (Read Only Memory).
24     )
25
26 ---
27     invariant int x = 3;    // x is set to 3
28     invariant int y;    // y is set to int.init, which is 0
29     x = 4;          // error, x is invariant
30     y = 5;          // error, y is invariant
31 ---
32
33     $(P
34     The initializer for an invariant declaration must be evaluatable
35     at compile time:
36     )
37
38 ---
39     int foo(int f) { return f * 3; }
40     int i = 5;
41     invariant int x = 3 * 4;    // ok, 12
42     invariant int y = i + 1;    // error, cannot evaluate at compile time
43     invariant int z = foo(2) + 1;   // ok, foo(2) can be evaluated at compile time, 7
44 ---
45
46     $(P
47     Data referred to by an invariant is also invariant:
48     )
49
50 ---
51     invariant char[] s = "foo";
52     s[0] = 'a';     // error, invariant
53 ---
54
55     $(P
56     An implementation is allowed to replace an instance of an invariant
57     declaration with the initializer for that declaration.
58     Therefore, it is not legal to take the address of an invariant:
59     )
60
61 ---
62     invariant int i = 3;
63     invariant* p = &i;  // error, cannot take address of invariant
64 ---
65
66     $(P
67     Invariant members of a class or struct do not take up
68     any space in instances of those objects:
69     )
70
71 ---
72     struct S
73     {   int x;
74         invariant int y;
75     }
76
77     writefln(S.sizeof); // prints 4, not 8
78 ---
79
80     $(P
81     The type of an invariant declaration is itself invariant.
82     )
83
84 <h2>Const Storage Class</h2>
85
86     $(P
87     A const declaration is exactly like an invariant declaration,
88     with the following differences:
89     )
90
91     $(UL
92     $(LI Any data referenced by the const declaration cannot be
93     changed from the const declaration, but it might be changed
94     by other references to the same data.)
95
96     $(LI The type of a const declaration is itself const.)
97     )
98
99 <h2>Final Storage Class</h2>
100
101     $(P
102     A final declaration is one that, once initialized, can never
103     change its value.
104     )
105
106 ---
107     final int x = 3;
108     x = 4;      // error, x is final
109 ---
110
111     $(P
112     Final declarations can be initialized either by an initializer,
113     or by a constructor:
114     )
115
116 ---
117     final int x;
118     static this()
119     {
120         x = 4;  // ok, can initialize final x inside constructor
121         x = 5;  // still ok, because still in constructor
122     }
123     ...
124     x = 6;      // error, x is final
125
126     class C
127     {
128         final int s;
129         this()
130         {   s = 3;  // ok, can initialize in constructor
131         }
132     }
133 ---
134
135     $(P
136     Final declarations are stored and do take up space,
137     therefore their address can be taken.
138     )
139
140     $(P
141     Taking the address of a final variable of type T results in a
142     type that's const(T)*.
143     )
144
145 ---
146     final int x = 3;
147     auto p = &x;        // p is const(int)*
148     *p = 4;         // error, *p is const
149 ---
150
151     $(P
152     Final declarations are themselves neither invariant nor const.
153     )
154
155 ---
156     int x = 4;
157     final int* p = &x;
158     p = null;       // error, p is final
159     *p = 3;         // ok, x is now 3
160 ---
161
162 <h2>Invariant Type</h2>
163
164     $(P
165     Data that will never change its value can be typed as invariant.
166     The invariant keyword can be used as a $(I type constructor):
167     )
168
169 ---
170     invariant(char)[] s = "hello";
171 ---
172
173     $(P
174     The invariant applies to the type within the following parentheses.
175     So, while s can be assigned new values, the contents of s[] cannot
176     be:
177     )
178
179 ---
180     s[0] = 'b'; // error, s[] is invariant
181     s = null;   // ok, s itself is not invariant
182 ---
183
184     $(P
185     Invariantness is transitive, meaning it applies to anything that
186     can be referenced from the invariant type:
187     )
188
189 ---
190     invariant(char*)** p = ...;
191     p = ...;    // ok, p is not final
192     *p = ...;   // *p is not invariant
193     **p = ...;  // error, **p is invariant
194     ***p = ...; // error, ***p is invariant
195 ---
196
197     $(P
198     The invariantness also only applies to what is referred to, not
199     the declaration itself:
200     )
201
202 ---
203     invariant(char*) p = ...;
204     p = ...;    // ok, invariant doesn't apply to p itself
205     *p = ...;   // error, invariant applies to what p refers to
206 ---
207
208 <h2>Creating Invariant Data</h2>
209
210     $(P
211     The first way is to use a literal that is already invariant,
212     such as string literals. String literals are always invariant.
213     )
214
215 ---
216     auto s = "hello";   // s is invariant(char)[5]
217     char[] p = "world"; // error, cannot implicitly convert invariant
218                 // to mutable
219 ---
220
221     $(P
222     The second way is to cast data to invariant.
223     When doing so, it is up to the programmer to ensure that no
224     other mutable references to the same data exist.
225     )
226
227 ---
228     char[] s = ...;
229     invariant(char)[] p = cast(invariant)s;     // undefined behavior
230     invariant(char)[] p = cast(invariant)s.dup; // ok, unique reference
231 ---
232
233     $(P
234     The .idup property is a convenient way to create an invariant
235     copy of an array:
236     )
237
238 ---
239     auto p = s.idup;
240     p[0] = ...;   // error, p[] is invariant
241 ---
242
243 <h2>Removing Invariant With A Cast</h2>
244
245     $(P
246     The invariant type can be removed with a cast:
247     )
248
249 ---
250     invariant int* p = ...;
251     int* q = cast(int*)p;
252 ---
253
254     $(P
255     This does not mean, however, that one can change the data:
256     )
257
258 ---
259     *q = 3; // allowed by compiler, but result is undefined behavior
260 ---
261
262     $(P
263     The ability to cast away invariant-correctness is necessary in
264     some cases where the static typing is incorrect and not fixable, such
265     as when referencing code in a library one cannot change.
266     Casting is, as always, a blunt and effective instrument, and
267     when using it to cast away invariant-correctness, one must assume
268     the responsibility to ensure the invariantness of the data, as
269     the compiler will no longer be able to statically do so.
270     )
271
272 <h2>Invariant Doesn't Apply To Declared Symbols</h2>
273
274     $(P
275     Consider the struct:
276     )
277
278 ---
279     struct S
280     {
281         int x;
282         int* p;
283     }
284 ---
285
286     $(P
287     In order to be able to use structs as user-defined wrappers
288     for builtin types, it must be possible to declare a struct instance
289     as having its members be mutable, but what it refers to to
290     not be mutable. But all that's syntactically available is:
291     )
292
293 ---
294     invariant(S) s;
295 ---
296
297     $(P
298     Therefore, the invariant qualifier doesn't apply to the symbol
299     itself being declared. It only applies to anything indirectly
300     referenced by the symbol. Hence,
301     )
302
303 ---
304     s.x = 3;   // ok
305     *s.p = 3;  // error, it's invariant
306 ---
307
308     $(P
309     For consistency's sake, then this must apply generally:
310     )
311
312 ---
313     int x;
314     invariant(int*) p;
315     p = cast(invariant)&x;    // ok
316     *p = 3;    // error, invariant
317
318     invariant(int) y;
319     y = 3;        // ok
320     auto q = cast(invariant)&y;  // q's type is invariant(int)*
321     *q = 4;       // error, invariant
322 ---
323
324     $(P
325     A similar situation applies to classes. Given:
326     )
327
328 ---
329     class C
330     {
331         int x;
332         int* p;
333     }
334
335     invariant(C) c;
336     c = new C;      // (1) ok
337     c.x = 3;        // (2) error, invariant
338     *c.p = 4;       // (3) error, invariant
339 ---
340
341     $(P
342     Note that the c.x is an error, while the s.x is not. The reason is
343     that c is already a reference type - so the invariant does not
344     apply to c itself (1), but it does apply to what c refers to (2) and
345     anything transitively referred to (3).
346     )
347
348 <h2>Invariant Member Functions</h2>
349
350     $(P
351     Invariant member functions are guaranteed that the object
352     and anything referred to by the this reference is invariant.
353     They are declared as:
354     )
355
356 ---
357     struct S
358     {   int x;
359
360         invariant void foo()
361         {
362         x = 4;  // error, x is invariant
363         this.x = 4;   // error, x is invariant
364         }
365     }
366 ---
367
368 <h2>Const Type</h2>
369
370     $(P
371     Const types are like invariant types, except that const
372     forms a read-only $(I view) of data. Other aliases to that
373     same data may change it at any time.
374     )
375
376 <h2>Const Member Functions</h2>
377
378     $(P
379     Const member functions are functions that are not allowed to
380     change any part of the object through the member function's
381     this reference.
382     )
383
384 <h2>Implicit Conversions</h2>
385
386     $(P
387     Mutable and invariant types can be implicitly converted to const.
388     Mutable types cannot be implicitly converted to invariant,
389     and vice versa.
390     )
391
392 <h2>Comparing D Invariant, Const and Final with C++ Const</h2>
393
394     <table border=2 cellpadding=4 cellspacing=0 class="comp">
395     <caption>Final, Const, Invariant Comparison</caption>
396
397     <thead>
398     $(TR
399     $(TH Feature)
400     $(TH D)
401     $(TH C++98)
402     )
403     </thead>
404
405     <tbody>
406
407     $(TR
408     $(TD final keyword)
409     $(TD Yes)
410     $(TD No)
411     )
412
413     $(TR
414     $(TD const keyword)
415     $(TD Yes)
416     $(TD Yes)
417     )
418
419     $(TR
420     $(TD invariant keyword)
421     $(TD Yes)
422     $(TD No)
423     )
424
425     $(TR
426     $(TD const notation)
427     $(TD Functional:
428 ---
429 // ptr to const ptr to const int
430 const(int*)* p;
431 ---
432     )
433     $(TD Postfix:
434 $(CPPCODE
435 // ptr to const ptr to const int
436 const int *const *p;
437 )
438     )
439     )
440
441     $(TR
442     $(TD transitive const)
443     $(TD Yes:
444 ---
445 const int** p;  // const ptr to const ptr to const int
446 **p = 3;    // error
447 ---
448      )
449     $(TD No:
450 $(CPPCODE
451 int** const p; // const ptr to ptr to int
452 **p = 3;    // ok
453 )
454      )
455     )
456
457     $(TR
458     $(TD cast away const)
459     $(TD Yes:
460 ---
461 const(int)* p;   // ptr to const int
462 int* q = cast(int*)p; // ok
463 ---
464     )
465     $(TD Yes:
466 $(CPPCODE
467 const int* p;   // ptr to const int
468 int* q = const_cast&lt;int*&gt;p; // ok
469 )
470     )
471     )
472
473     $(TR
474     $(TD modification after casting away const)
475     $(TD No:
476 ---
477 const(int)* p;   // ptr to const int
478 int* q = cast(int*)p;
479 *q = 3;   // undefined behavior
480 ---
481     )
482     $(TD Yes:
483 $(CPPCODE
484 const int* p;   // ptr to const int
485 int* q = const_cast&lt;int*&gt;p;
486 *q = 3;   // ok
487 )
488     )
489     )
490
491     $(TR
492     $(TD overloading of top level const)
493     $(TD No:
494 ---
495 void foo(int x);
496 void foo(const int x);  // error
497 ---
498     )
499     $(TD No:
500 $(CPPCODE
501 void foo(int x);
502 void foo(const int x);  // error
503 )
504     )
505     )
506
507     $(TR
508     $(TD aliasing of const with mutable)
509     $(TD Yes:
510 ---
511 void foo(const int* x, int* y)
512 {
513    bar(*x); // bar(3)
514    *y = 4;
515    bar(*x); // bar(4)
516 }
517 ...
518 int i = 3;
519 foo(&i, &i);
520 ---
521     )
522     $(TD Yes:
523 $(CPPCODE
524 void foo(const int* x, int* y)
525 {
526    bar(*x); // bar(3)
527    *y = 4;
528    bar(*x); // bar(4)
529 }
530 ...
531 int i = 3;
532 foo(&i, &i);
533 )
534     )
535     )
536
537     $(TR
538     $(TD aliasing of invariant with mutable)
539     $(TD Yes:
540 ---
541 void foo(invariant int* x, int* y)
542 {
543    bar(*x); // bar(3)
544    *y = 4;  // undefined behavior
545    bar(*x); // bar(??)
546 }
547 ...
548 int i = 3;
549 foo(cast(invariant)&i, &i);
550 ---
551     )
552     $(TD No invariants)
553     )
554
555     $(TR
556     $(TD type of string literal)
557     $(TD invariant(char)[])
558     $(TD const char*)
559     )
560
561
562     $(TR
563     $(TD implicit conversion of string literal to non-const)
564     $(TD not allowed)
565     $(TD allowed, but deprecated)
566     )
567
568     </tbody>
569     </table>
570
571 )
572
573 Macros:
574     TITLE=Final$(COMMA) Const$(COMMA) and Invariant
575     WIKI=FinalConstInvariant
576     NO=<td class="compNo">No</td>
577     NO1=<td class="compNo"><a href="$1">No</a></td>
578     YES=<td class="compYes">Yes</td>
579     YES1=<td class="compYes"><a href="$1">Yes</a></td>
580     D_CODE = <pre class="d_code2">$0</pre>
581     CPPCODE2 = <pre class="cppcode2">$0</pre>
582     ERROR = $(RED $(B error))
583     COMMA=,
584 META_KEYWORDS=D Programming Language, const,
585 final, invariant
586 META_DESCRIPTION=Comparison of const between the
587 D programming language, C++, and C++0x
Note: See TracBrowser for help on using the browser.