forked from dlang/dlang.org
-
Notifications
You must be signed in to change notification settings - Fork 0
/
declaration.dd
805 lines (644 loc) · 24 KB
/
declaration.dd
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
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
Ddoc
$(SPEC_S Declarations,
$(HEADERNAV_TOC)
$(GRAMMAR
$(GNAME Declaration):
$(GLINK2 function, FuncDeclaration)
$(GLINK VarDeclarations)
$(GLINK AliasDeclaration)
$(GLINK AliasAssign)
$(GLINK2 struct, AggregateDeclaration)
$(GLINK2 enum, EnumDeclaration)
$(GLINK2 module, ImportDeclaration)
$(GLINK2 version, ConditionalDeclaration)
$(GLINK2 version, StaticForeachDeclaration)
$(GLINK2 version, StaticAssert)
)
$(GRAMMAR
$(GNAME VarDeclarations):
$(GLINK StorageClasses)$(OPT) $(GLINK2 type, BasicType) $(GLINK Declarators) $(D ;)
$(GLINK AutoDeclaration)
$(GNAME Declarators):
$(GLINK DeclaratorInitializer)
$(GLINK DeclaratorInitializer) $(D ,) $(GLINK DeclaratorIdentifierList)
$(GNAME DeclaratorInitializer):
$(GLINK VarDeclarator)
$(GLINK VarDeclarator) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK Initializer)
$(GLINK AltDeclarator)
$(GLINK AltDeclarator) $(D =) $(GLINK Initializer)
$(GNAME DeclaratorIdentifierList):
$(GLINK DeclaratorIdentifier)
$(GLINK DeclaratorIdentifier) $(D ,) $(GSELF DeclaratorIdentifierList)
$(GNAME DeclaratorIdentifier):
$(GLINK VarDeclaratorIdentifier)
$(GLINK AltDeclaratorIdentifier)
$(GNAME VarDeclaratorIdentifier):
$(GLINK_LEX Identifier)
$(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK Initializer)
$(GNAME AltDeclaratorIdentifier):
$(GLINK2 type, TypeSuffixes) $(GLINK_LEX Identifier) $(GLINK AltDeclaratorSuffixes)$(OPT)
$(GLINK2 type, TypeSuffixes) $(GLINK_LEX Identifier) $(GLINK AltDeclaratorSuffixes)$(OPT) $(D =) $(GLINK Initializer)
$(GLINK2 type, TypeSuffixes)$(OPT) $(GLINK_LEX Identifier) $(GLINK AltDeclaratorSuffixes)
$(GLINK2 type, TypeSuffixes)$(OPT) $(GLINK_LEX Identifier) $(GLINK AltDeclaratorSuffixes) $(D =) $(GLINK Initializer)
$(GNAME Declarator):
$(GLINK VarDeclarator)
$(GLINK AltDeclarator)
$(GNAME VarDeclarator):
$(GLINK2 type, TypeSuffixes)$(OPT) $(GLINK_LEX Identifier)
$(GNAME AltDeclarator):
$(GLINK2 type, TypeSuffixes)$(OPT) $(GLINK_LEX Identifier) $(GLINK AltDeclaratorSuffixes)
$(GLINK2 type, TypeSuffixes)$(OPT) $(D $(LPAREN)) $(GLINK AltDeclaratorInner) $(D $(RPAREN))
$(GLINK2 type, TypeSuffixes)$(OPT) $(D $(LPAREN)) $(GLINK AltDeclaratorInner) $(D $(RPAREN)) $(GLINK AltFuncDeclaratorSuffix)
$(GLINK2 type, TypeSuffixes)$(OPT) $(D $(LPAREN)) $(GLINK AltDeclaratorInner) $(D $(RPAREN)) $(GLINK AltDeclaratorSuffixes)
$(GNAME AltDeclaratorInner):
$(GLINK2 type, TypeSuffixes)$(OPT) $(GLINK_LEX Identifier)
$(GLINK2 type, TypeSuffixes)$(OPT) $(GLINK_LEX Identifier) $(GLINK AltFuncDeclaratorSuffix)
$(GLINK AltDeclarator)
$(GNAME AltDeclaratorSuffixes):
$(GLINK AltDeclaratorSuffix)
$(GLINK AltDeclaratorSuffix) $(GSELF AltDeclaratorSuffixes)
$(GNAME AltDeclaratorSuffix):
$(D [ ])
$(D [) $(GLINK2 expression, AssignExpression) $(D ])
$(D [) $(GLINK2 type, Type) $(D ])
$(GNAME AltFuncDeclaratorSuffix):
$(GLINK2 function, Parameters) $(GLINK2 function, MemberFunctionAttributes)$(OPT)
)
$(GRAMMAR
$(GNAME StorageClasses):
$(GLINK StorageClass)
$(GLINK StorageClass) $(GSELF StorageClasses)
$(GNAME StorageClass):
$(MULTICOLS 5, $(GLINK2 attribute, LinkageAttribute)
$(GLINK2 attribute, AlignAttribute)
$(GLINK2 attribute, AtAttribute)
$(D deprecated)
$(D enum)
$(D static)
$(RELATIVE_LINK2 extern, $(D extern))
$(D abstract)
$(D final)
$(D override)
$(D synchronized)
$(D auto)
$(D scope)
$(D const)
$(D immutable)
$(D inout)
$(D shared)
$(D __gshared)
$(GLINK2 attribute, Property)
$(D nothrow)
$(D pure)
$(D ref))
)
$(GRAMMAR
$(GNAME Initializer):
$(GLINK VoidInitializer)
$(GLINK NonVoidInitializer)
$(GNAME NonVoidInitializer):
$(GLINK ExpInitializer)
$(GLINK ArrayInitializer)
$(GLINK StructInitializer)
$(GNAME ExpInitializer):
$(GLINK2 expression, AssignExpression)
$(GNAME ArrayInitializer):
$(D [) $(GLINK ArrayMemberInitializations)$(OPT) $(D ])
$(GNAME ArrayMemberInitializations):
$(GLINK ArrayMemberInitialization)
$(GLINK ArrayMemberInitialization) $(D ,)
$(GLINK ArrayMemberInitialization) $(D ,) $(GSELF ArrayMemberInitializations)
$(GNAME ArrayMemberInitialization):
$(GLINK NonVoidInitializer)
$(GLINK2 expression, AssignExpression) $(D :) $(GLINK NonVoidInitializer)
$(GNAME StructInitializer):
$(D {) $(GLINK StructMemberInitializers)$(OPT) $(D })
$(GNAME StructMemberInitializers):
$(GLINK StructMemberInitializer)
$(GLINK StructMemberInitializer) $(D ,)
$(GLINK StructMemberInitializer) $(D ,) $(GSELF StructMemberInitializers)
$(GNAME StructMemberInitializer):
$(GLINK NonVoidInitializer)
$(GLINK_LEX Identifier) $(D :) $(GLINK NonVoidInitializer)
)
$(H2 $(LNAME2 declaration_syntax, Declaration Syntax))
$(P Declaration syntax generally reads right to left, including arrays:)
--------------------
int x; // x is an int
int* x; // x is a pointer to int
int** x; // x is a pointer to a pointer to int
int[] x; // x is an array of ints
int*[] x; // x is an array of pointers to ints
int[]* x; // x is a pointer to an array of ints
int[3] x; // x is a static array of 3 ints
int[3][5] x; // x is a static array of 5 static arrays of 3 ints
int[3]*[5] x; // x is a static array of 5 pointers to static arrays of 3 ints
--------------------
$(H3 $(LNAME2 pointers-to-functions, Pointers to Functions))
$(P
Pointers to functions are declared using the $(D function) keyword:
)
--------------------
int function(char) x; // x is a pointer to
// a function taking a char argument
// and returning an int
int function(char)[] x; // x is an array of
// pointers to functions
// taking a char argument
// and returning an int
--------------------
$(H3 $(LNAME2 c-style-declarations, C-Style Declarations))
$(P
C-style array, function pointer and pointer to array declarations are deprecated:
)
--------------------
int x[3]; // x is a static array of 3 ints
int x[3][5]; // x is a static array of 3 arrays of 5 ints
int (*x[5])[3]; // x is a static array of 5 pointers to static arrays of 3 ints
int (*x)(char); // x is a pointer to a function taking a char argument
// and returning an int
int (*[] x)(char); // x is an array of pointers to functions
// taking a char argument and returning an int
--------------------
$(H3 $(LNAME2 declaring-multiple-symbols, Declaring Multiple Symbols))
$(P
In a declaration declaring multiple symbols, all the declarations
must be of the same type:
)
--------------------
int x,y; // x and y are ints
int* x,y; // x and y are pointers to ints
int[] x,y; // x and y are arrays of ints
// invalid C-style declarations
int x,*y; // error, multiple types
int x[],y; // error, multiple types
--------------------
$(H2 $(LEGACY_LNAME2 AutoDeclaration, auto-declaration, Implicit Type Inference))
$(GRAMMAR
$(GNAME AutoDeclaration):
$(GLINK StorageClasses) $(GLINK AutoAssignments) $(D ;)
$(GNAME AutoAssignments):
$(GLINK AutoAssignment)
$(GSELF AutoAssignments) $(D ,) $(GLINK AutoAssignment)
$(GNAME AutoAssignment):
$(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK Initializer)
)
$(P If a declaration starts with a $(I StorageClass) and has
a $(I NonVoidInitializer) from which the type can be inferred,
the type on the declaration can be omitted.
)
----------
static x = 3; // x is type int
auto y = 4u; // y is type uint
auto s = "Apollo"; // s is type immutable(char)[] i.e., string
class C { ... }
auto c = new C(); // c is a handle to an instance of class C
----------
$(P The $(I NonVoidInitializer) cannot contain forward references
(this restriction may be removed in the future).
The implicitly inferred type is statically bound
to the declaration at compile time, not run time.
)
$(P An $(GLINK2 expression, ArrayLiteral)
is inferred to be a dynamic array
type rather than a static array:)
---
auto v = ["resistance", "is", "useless"]; // type is string[], not string[3]
---
$(H2 $(LNAME2 alias, Alias Declarations))
$(GRAMMAR
$(GNAME AliasDeclaration):
$(D alias) $(GLINK StorageClasses)$(OPT) $(GLINK2 type, BasicType) $(GLINK Declarators) $(D ;)
$(D alias) $(GLINK StorageClasses)$(OPT) $(GLINK2 type, BasicType) $(GLINK2 function, FuncDeclarator) $(D ;)
$(D alias) $(GLINK AliasAssignments) $(D ;)
$(GNAME AliasAssignments):
$(GLINK AliasAssignment)
$(GSELF AliasAssignments) $(D ,) $(GLINK AliasAssignment)
$(GNAME AliasAssignment):
$(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK StorageClasses)$(OPT) $(GLINK2 type, Type)
$(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK2 expression, FunctionLiteral)
$(GLINK_LEX Identifier) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK StorageClasses)$(OPT) $(GLINK2 type, BasicType) $(GLINK2 function, Parameters) $(GLINK2 function, MemberFunctionAttributes)$(OPT)
)
$(P $(I AliasDeclaration)s create a symbol that is an alias for another type,
and can be used anywhere that other type may appear.
)
--------------------
alias myint = abc.Foo.bar;
--------------------
$(P
Aliased types are semantically identical to the types they are aliased to. The
debugger cannot distinguish between them, and there is no difference as far as function
overloading is concerned. For example:
)
--------------------
alias myint = int;
void foo(int x) { ... }
void foo(myint m) { ... } // error, multiply defined function foo
--------------------
$(P A symbol can be declared as an $(I alias) of another symbol.
For example:
)
---
import planets;
alias myAlbedo = planets.albedo;
...
int len = myAlbedo("Saturn"); // actually calls planets.albedo()
---
$(P
The following alias declarations are valid:
)
--------------------
template Foo2(T) { alias t = T; }
alias t1 = Foo2!(int);
alias t2 = Foo2!(int).t;
alias t3 = t1.t;
alias t4 = t2;
t1.t v1; // v1 is type int
t2 v2; // v2 is type int
t3 v3; // v3 is type int
t4 v4; // v4 is type int
alias Fun = int(string p);
int fun(string){return 0;}
static assert(is(typeof(fun) == Fun));
alias MemberFun1 = int() const;
alias MemberFun2 = const int();
// leading attributes apply to the func, not the return type
static assert(is(MemberFun1 == MemberFun2));
--------------------
$(P
Aliased symbols are useful as a shorthand for a long qualified
symbol name, or as a way to redirect references from one symbol
to another:
)
--------------------
version (Win32)
{
alias myfoo = win32.foo;
}
version (linux)
{
alias myfoo = linux.bar;
}
--------------------
$(P
Aliasing can be used to `import` a symbol from an import into the
current scope:
)
--------------------
alias strlen = string.strlen;
--------------------
$(P
Aliases can also `import` a set of overloaded functions, that can
be overloaded with functions in the current scope:
)
--------------------
class A
{
int foo(int a) { return 1; }
}
class B : A
{
int foo( int a, uint b ) { return 2; }
}
class C : B
{
int foo( int a ) { return 3; }
alias foo = B.foo;
}
class D : C
{
}
void test()
{
D b = new D();
int i;
i = b.foo(1, 2u); // calls B.foo
i = b.foo(1); // calls C.foo
}
--------------------
$(P
$(B Note:) Type aliases can sometimes look indistinguishable from
alias declarations:
)
--------------------
alias abc = foo.bar; // is it a type or a symbol?
--------------------
$(P
The distinction is made in the semantic analysis pass.
)
$(P Aliases cannot be used for expressions:)
-----------
struct S
{
static int i;
static int j;
}
alias a = S.i; // OK, `S.i` is a symbol
alias b = S.j; // OK. `S.j` is also a symbol
alias c = a + b; // illegal, `a + b` is an expression
a = 2; // sets `S.i` to `2`
b = 4; // sets `S.j` to `4`
-----------
$(P Aliases can be used to call a function with different default
arguments, change an argument from required to default or vice versa:)
-----------
import std.stdio : writefln;
void main() {
Foo foo = &foofoo;
foo(); // prints v: 6
foo(8); // prints v: 8
Bar bar = &barbar;
// bar(4); // compilation error, because the `Bar` alias
// requires an explicit 2nd argument
barbar(4); // prints a: 4, b: 6, c: 7
bar(4, 5); // prints a: 4, b: 5, c: 9
bar(4, 5, 6); // prints a: 4, b: 5, c: 6
Baz baz = &barbar;
baz(); // prints a: 2, b: 3, c: 4
}
alias Foo = void function(int=6);
alias Bar = void function(int, int, int=9);
alias Baz = void function(int=2, int=3, int=4);
void foofoo(int v = 6) {
writefln("v: %d", v);
}
void barbar(int a, int b = 6, int c = 7) {
writefln("a: %d, b: %d, c: %d", a, b, c);
}
-----------
$(H2 $(LNAME2 AliasAssign, Alias Assign))
$(GRAMMAR
$(GNAME AliasAssign):
$(GLINK_LEX Identifier) $(D =) $(GLINK2 type, Type)
)
$(P An $(GLINK AliasDeclaration) can have a new value assigned to it with an
$(I AliasAssign):)
---
template Gorgon(T)
{
alias A = long;
A = T; // assign new value to A
alias Gorgon = A;
}
pragma(msg, Gorgon!int); // prints int
---
$(UL
$(LI The $(I AliasAssign) and its corresponding $(I AliasDeclaration) must both be
declared in the same $(GLINK2 template, TemplateDeclaration).)
$(LI The corresponding $(I AliasDeclaration) must appear lexically before the
$(I AliasAssign).)
$(LI The corresponding $(I AliasDeclaration) may not refer to overloaded symbols.)
$(LI The value of an $(I AliasDeclaration) or left hand side (lvalue) of an $(I AliasAssign) may not be used prior
to another $(I AliasAssign) to the same lvalue other than in the right hand side of that $(I AliasAssign).)
)
$(BEST_PRACTICE
$(I AliasAssign) is particularly useful when using an iterative
computation rather than a recursive one, as it avoids creating
the large number of intermediate templates that the recursive one
engenders.
---
template AliasSeq(T...) { alias AliasSeq = T; }
static if (0) // recursive method for comparison
{
template Reverse(T...)
{
static if (T.length == 0)
alias Reverse = AliasSeq!();
else
alias Reverse = AliasSeq!(Reverse!(T[1 .. T.length]), T[0]);
}
}
else // iterative method minimizes template instantiations
{
template Reverse(T...)
{
alias A = AliasSeq!();
static foreach (t; T)
A = AliasSeq!(t, A); // Alias Assign
alias Reverse = A;
}
}
enum X = 3;
alias TK = Reverse!(int, const uint, X);
pragma(msg, TK); // prints tuple(3, (const(uint)), (int))
---
)
$(H2 $(LNAME2 alias-reassignment, Alias Reassignment))
$(GRAMMAR
$(GNAME AliasReassignment):
$(GLINK_LEX Identifier) $(D =) $(GLINK StorageClasses)$(OPT) $(GLINK2 type, Type)
$(GLINK_LEX Identifier) $(D =) $(GLINK2 expression, FunctionLiteral)
$(GLINK_LEX Identifier) $(D =) $(GLINK StorageClasses)$(OPT) $(GLINK2 type, BasicType) $(GLINK2 function, Parameters) $(GLINK2 function, MemberFunctionAttributes)$(OPT)
)
$(P An alias declaration inside a template can be reassigned a new value.)
---
template staticMap(alias F, T...)
{
alias A = AliasSeq!();
static foreach (t; T)
A = AliasSeq!(A, F!T); // alias reassignment
alias staticMap = A;
}
---
$(P The $(I Identifier) must resolve to a lexically preceding $(GLINK AliasDeclaration).
Both must be members of the same $(GLINK2 template, TemplateDeclaration).
)
$(P The right hand side of the $(I AliasReassignment) replaces the right hand side of the
$(I AliasDeclaration).
)
$(P Once the $(I AliasDeclaration) has been referred to in any context other than the
right hand side of an $(I AliasReassignment) it can no longer be reassigned.
)
$(RATIONALE Alias reassignment can result in faster compile times and lowered memory consumption,
and requires significantly simpler code than the alternative recursive method.)
$(H2 $(LNAME2 extern, Extern Declarations))
$(P Variable declarations with the storage class $(D extern) are not allocated
storage within the module. They must be defined in some other object file with a
matching name which is then linked in.)
$(P An $(D extern) declaration can optionally be followed by an $(D extern)
$(LINK2 attribute.html$(HASH)linkage, linkage attribute). If there is no linkage
attribute it defaults to $(D extern(D)):)
---------------
// variable allocated and initialized in this module with C linkage
extern(C) int foo;
// variable allocated outside this module with C linkage
// (e.g. in a statically linked C library or another module)
extern extern(C) int bar;
---------------
$(BEST_PRACTICE
$(OL
$(LI The primary usefulness of $(I Extern Declarations) is to
connect with global variables declarations and functions in C or C++ files.)
))
$(H2 $(LNAME2 void_init, Void Initializations))
$(GRAMMAR
$(GNAME VoidInitializer):
$(D void)
)
$(P Normally, variables are initialized either with an explicit
$(GLINK Initializer) or are set to the default value for the
type of the variable. If the $(I Initializer) is $(D void),
however, the variable is not initialized. If its value is
used before it is set, undefined program behavior will result.
)
$(IMPLEMENTATION_DEFINED If a void initialized variable's value is
used before it is set, its value is implementation defined.
---
void bad()
{
int x = void;
writeln(x); // print implementation defined value
}
---
)
$(UNDEFINED_BEHAVIOR If a void initialized variable's value is
used before it is set, and the value is a reference, pointer or an instance
of a struct with an invariant, the behavior is undefined.
---
void muchWorse()
{
char[] p = void;
writeln(p); // may result in apocalypse
}
---
)
$(BEST_PRACTICE
$(OL
$(LI Void initializers are useful when a static array is on the stack,
but may only be partially used, such as a temporary buffer.
Void initializers will potentially speed up the code, but they introduce risk, since one must ensure
that array elements are always set before read.)
$(LI The same is true for structs.)
$(LI Use of void initializers is rarely useful for individual local variables,
as a modern optimizer will remove the dead store of its initialization if it is
initialized later.)
$(LI For hot code paths, it is worth profiling to see if the void initializer
actually improves results.)
)
)
$(H2 $(LNAME2 global_static_init, Global and Static Initializers))
$(P The $(GLINK Initializer) for a global or static variable must be
evaluatable at compile time.
Runtime initialization is done with static constructors.
)
$(IMPLEMENTATION_DEFINED
$(OL
$(LI Whether some pointers can be initialized with the addresses of other
functions or data.)
))
$(H2 $(LNAME2 typequal_vs_storageclass, Type Qualifiers vs. Storage Classes))
$(P Type qualifer and storage classes are distinct.)
$(P A $(I type qualifier) creates a derived type from an existing base
type, and the resulting type may be used to create multiple instances
of that type.)
$(P For example, the $(D immutable) type qualifier can be used to
create variables of immutable type, such as:)
--------
immutable(int) x; // typeof(x) == immutable(int)
immutable(int)[] y; // typeof(y) == immutable(int)[]
// typeof(y[0]) == immutable(int)
// Type constructors create new types that can be aliased:
alias ImmutableInt = immutable(int);
ImmutableInt z; // typeof(z) == immutable(int)
--------
$(P A $(I storage class), on the other hand, does not create a new
type, but describes only the kind of storage used by the variable or
function being declared. For example, a member function can be declared
with the $(D const) storage class to indicate that it does not modify
its implicit $(D this) argument:)
--------
struct S
{
int x;
int method() const
{
//x++; // Error: this method is const and cannot modify this.x
return x; // OK: we can still read this.x
}
}
--------
$(P Although some keywords can be used both as a type qualifier and a
storage class, there are some storage classes that cannot be used to
construct new types, such as $(D ref):)
--------
// ref declares the parameter x to be passed by reference
void func(ref int x)
{
x++; // so modifications to x will be visible in the caller
}
void main()
{
auto x = 1;
func(x);
assert(x == 2);
// However, ref is not a type qualifier, so the following is illegal:
ref(int) y; // Error: ref is not a type qualifier.
}
--------
$(P Functions can also be declared as `ref`, meaning their return value is
passed by reference:)
--------
ref int func2()
{
static int y = 0;
return y;
}
void main()
{
func2() = 2; // The return value of func2() can be modified.
assert(func2() == 2);
// However, the reference returned by func2() does not propagate to
// variables, because the 'ref' only applies to the return value itself,
// not to any subsequent variable created from it:
auto x = func2();
static assert(is(typeof(x) == int)); // N.B.: *not* ref(int);
// there is no such type as ref(int).
x++;
assert(x == 3);
assert(func2() == 2); // x is not a reference to what func2() returned; it
// does not inherit the ref storage class from func2().
}
--------
$(P Some keywords, such as $(D const), can be used
both as a type qualifier and a storage class.
The distinction is determined by the syntax where it appears.)
---
struct S
{
/* Is const here a type qualifier or a storage class?
* Is the return value const(int), or is this a const function that returns
* (mutable) int?
*/
const int* func() // a const function
{
++p; // error, this.p is const
return p; // error, cannot convert const(int)* to int*
}
const(int)* func() // a function returning a pointer to a const int
{
++p; // ok, this.p is mutable
return p; // ok, int* can be implicitly converted to const(int)*
}
int* p;
}
---
$(BEST_PRACTICE To avoid confusion, the type qualifier
syntax with parentheses should be used for return types,
and function storage classes should be written on the right-hand side of the
declaration instead of the left-hand side where it may be visually
confused with the return type:
---
struct S
{
// Now it is clear that the 'const' here applies to the return type:
const(int) func1() { return 1; }
// And it is clear that the 'const' here applies to the function:
int func2() const { return 1; }
}
---
)
$(SPEC_SUBNAV_PREV_NEXT module, Modules, type, Types)
)
Macros:
CHAPTER=5
TITLE=Declarations