forked from dlang/dlang.org
/
declaration.dd
741 lines (599 loc) · 20.3 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
Ddoc
$(SPEC_S Declarations,
$(GRAMMAR
$(GNAME Declaration):
$(GLINK2 function, FuncDeclaration)
$(GLINK VarDeclarations)
$(GLINK AliasDeclaration)
$(GLINK2 struct, AggregateDeclaration)
$(GLINK2 enum, EnumDeclaration)
$(GLINK2 module, ImportDeclaration)
)
$(GRAMMAR
$(GNAME VarDeclarations):
$(GLINK StorageClasses)$(OPT) $(GLINK BasicType) $(GLINK Declarators) $(D ;)
$(GLINK AutoDeclaration)
$(GNAME Declarators):
$(I DeclaratorInitializer)
$(I 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 ,) $(I DeclaratorIdentifierList)
$(GNAME DeclaratorIdentifier):
$(GLINK VarDeclaratorIdentifier)
$(GLINK AltDeclaratorIdentifier)
$(GNAME VarDeclaratorIdentifier):
$(I Identifier)
$(I Identifier) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK Initializer)
$(GNAME AltDeclaratorIdentifier):
$(GLINK BasicType2) $(I Identifier) $(GLINK AltDeclaratorSuffixes)$(OPT)
$(GLINK BasicType2) $(I Identifier) $(GLINK AltDeclaratorSuffixes)$(OPT) $(D =) $(GLINK Initializer)
$(GLINK BasicType2)$(OPT) $(I Identifier) $(GLINK AltDeclaratorSuffixes)
$(GLINK BasicType2)$(OPT) $(I Identifier) $(GLINK AltDeclaratorSuffixes) $(D =) $(GLINK Initializer)
$(GNAME Declarator):
$(GLINK VarDeclarator)
$(GLINK AltDeclarator)
$(GNAME VarDeclarator):
$(GLINK BasicType2)$(OPT) $(I Identifier)
$(GNAME AltDeclarator):
$(GLINK BasicType2)$(OPT) $(I Identifier) $(GLINK AltDeclaratorSuffixes)
$(GLINK BasicType2)$(OPT) $(D $(LPAREN)) $(I AltDeclaratorX) $(D $(RPAREN))
$(GLINK BasicType2)$(OPT) $(D $(LPAREN)) $(I AltDeclaratorX) $(D $(RPAREN)) $(GLINK AltFuncDeclaratorSuffix)
$(GLINK BasicType2)$(OPT) $(D $(LPAREN)) $(I AltDeclaratorX) $(D $(RPAREN)) $(GLINK AltDeclaratorSuffixes)
$(GNAME AltDeclaratorX):
$(GLINK BasicType2)$(OPT) $(I Identifier)
$(GLINK BasicType2)$(OPT) $(I Identifier) $(GLINK AltFuncDeclaratorSuffix)
$(GLINK AltDeclarator)
$(GNAME AltDeclaratorSuffixes):
$(GLINK AltDeclaratorSuffix)
$(GLINK AltDeclaratorSuffix) $(I AltDeclaratorSuffixes)
$(GNAME AltDeclaratorSuffix):
$(D [ ])
$(D [) $(VEXPRESSION) $(D ])
$(D [) $(GLINK Type) $(D ])
$(GNAME AltFuncDeclaratorSuffix):
$(GLINK2 function, Parameters) $(GLINK2 function, MemberFunctionAttributes)$(OPT)
)
$(GRAMMAR
$(GNAME Type):
$(GLINK TypeCtors)$(OPT) $(GLINK BasicType) $(GLINK BasicType2)$(OPT)
$(GNAME TypeCtors):
$(GLINK TypeCtor)
$(GLINK TypeCtor) $(I TypeCtors)
$(GNAME TypeCtor):
$(D const)
$(D immutable)
$(D inout)
$(D shared)
$(GNAME BasicType):
$(GLINK BasicTypeX)
$(D .) $(GLINK IdentifierList)
$(GLINK IdentifierList)
$(GLINK Typeof)
$(GLINK Typeof) $(D .) $(GLINK IdentifierList)
$(GLINK TypeCtor) $(D $(LPAREN)) $(GLINK Type) $(D $(RPAREN))
$(GLINK2 grammar, TypeVector)
$(GNAME BasicTypeX):
$(MULTICOLS 5,
$(D bool)
$(D byte)
$(D ubyte)
$(D short)
$(D ushort)
$(D int)
$(D uint)
$(D long)
$(D ulong)
$(D char)
$(D wchar)
$(D dchar)
$(D float)
$(D double)
$(D real)
$(D ifloat)
$(D idouble)
$(D ireal)
$(D cfloat)
$(D cdouble)
$(D creal)
$(D void))
$(GNAME BasicType2):
$(GLINK BasicType2X) $(GLINK BasicType2)$(OPT)
$(GNAME BasicType2X):
$(D *)
$(D [ ])
$(D [) $(VEXPRESSION) $(D ])
$(D [) $(VEXPRESSION) .. $(VEXPRESSION) $(D ])
$(D [) $(GLINK Type) $(D ])
$(D delegate) $(GLINK2 function, Parameters) $(GLINK2 function, MemberFunctionAttributes)$(OPT)
$(D function) $(GLINK2 function, Parameters) $(GLINK2 function, FunctionAttributes)$(OPT)
$(GNAME IdentifierList):
$(I Identifier)
$(I Identifier) $(D .) $(I IdentifierList)
$(GLINK2 template, TemplateInstance)
$(GLINK2 template, TemplateInstance) $(D .) $(I IdentifierList)
)
$(GRAMMAR
$(GNAME StorageClasses):
$(GLINK StorageClass)
$(GLINK StorageClass) $(I StorageClasses)
$(GNAME StorageClass):
$(MULTICOLS 5, $(GLINK2 attribute, LinkageAttribute)
$(GLINK2 attribute, AlignAttribute)
$(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):
$(ASSIGNEXPRESSION)
$(GNAME ArrayInitializer):
$(D [) $(GLINK ArrayMemberInitializations)$(OPT) $(D ])
$(GNAME ArrayMemberInitializations):
$(GLINK ArrayMemberInitialization)
$(GLINK ArrayMemberInitialization) $(D ,)
$(GLINK ArrayMemberInitialization) $(D ,) $(I ArrayMemberInitializations)
$(GNAME ArrayMemberInitialization):
$(GLINK NonVoidInitializer)
$(ASSIGNEXPRESSION) $(D :) $(GLINK NonVoidInitializer)
$(GNAME StructInitializer):
$(D {) $(GLINK StructMemberInitializers)$(OPT) $(D })
$(GNAME StructMemberInitializers):
$(GLINK StructMemberInitializer)
$(GLINK StructMemberInitializer) $(D ,)
$(GLINK StructMemberInitializer) $(D ,) $(I StructMemberInitializers)
$(GNAME StructMemberInitializer):
$(GLINK NonVoidInitializer)
$(I Identifier) $(D :) $(GLINK NonVoidInitializer)
)
$(H3 Declaration Syntax)
$(P Declaration syntax generally reads right to left:)
--------------------
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
--------------------
$(P Arrays read right to left as well:)
--------------------
int[3] x; // x is an array of 3 ints
int[3][5] x; // x is an array of 5 arrays of 3 ints
int[3]*[5] x; // x is an array of 5 pointers to arrays of 3 ints
--------------------
$(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
--------------------
$(P
C-style array, function pointer and pointer to array declarations are deprecated:
)
--------------------
int x[3]; // x is an array of 3 ints
int x[3][5]; // x is an array of 3 arrays of 5 ints
int (*x[5])[3]; // x is an array of 5 pointers to 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
--------------------
$(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; // error, multiple types
int[] x,y; // x and y are arrays of ints
int x[],y; // error, multiple types
--------------------
$(H3 $(LEGACY_LNAME2 AutoDeclaration, auto-declaration, Implicit Type Inference))
$(GRAMMAR
$(GNAME AutoDeclaration):
$(GLINK StorageClasses) $(I AutoDeclarationX) $(D ;)
$(GNAME AutoDeclarationX):
$(I Identifier) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK Initializer)
$(I AutoDeclarationX) $(D ,) $(I 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 = "string"; // s is type immutable(char)[]
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 = ["hello", "world"]; // type is string[], not string[2]
---
$(H3 $(LNAME2 alias, Alias Declarations))
$(GRAMMAR
$(GNAME AliasDeclaration):
$(D alias) $(GLINK StorageClasses)$(OPT) $(GLINK BasicType) $(GLINK Declarators) $(D ;)
$(D alias) $(GLINK StorageClasses)$(OPT) $(GLINK BasicType) $(GLINK FuncDeclarator) $(D ;)
$(D alias) $(I AliasDeclarationX) $(D ;)
$(GNAME AliasDeclarationX):
$(I Identifier) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK StorageClasses)$(OPT) $(GLINK Type)
$(I AliasDeclarationX) $(D ,) $(I Identifier) $(GLINK2 template, TemplateParameters)$(OPT) $(D =) $(GLINK StorageClasses)$(OPT) $(GLINK Type)
)
$(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 string;
alias mylen = string.strlen;
...
int len = mylen("hello"); // actually calls string.strlen()
--------------------
$(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
--------------------
$(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 $(SINGLEQUOTE import) a symbol from an import into the
current scope:
)
--------------------
alias strlen = string.strlen;
--------------------
$(P
Aliases can also $(SINGLEQUOTE 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; }
S s;
alias a = s.i; // illegal, s.i is an expression
alias b = S.i; // ok
b = 4; // sets S.i to 4
-----------
$(H3 $(LNAME2 extern, Extern Declarations))
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.
The primary usefulness of this is to connect with global
variable declarations in C files.
$(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)):)
---------------
extern(C) int foo; // variable allocated and initialized in this module with C linkage
extern extern(C) int bar; // variable allocated outside this module with C linkage
// (e.g. in a statically linked C library or another module)
---------------
$(H3 $(LNAME2 typeof, $(D typeof)))
$(GRAMMAR
$(GNAME Typeof):
$(D typeof $(LPAREN)) $(EXPRESSION) $(D $(RPAREN))
$(D typeof $(LPAREN)) $(D return) $(D $(RPAREN))
)
$(P
$(I Typeof) is a way to specify a type based on the type
of an expression. For example:
)
--------------------
void func(int i)
{
typeof(i) j; // j is of type int
typeof(3 + 6.0) x; // x is of type double
typeof(1)* p; // p is of type pointer to int
int[typeof(p)] a; // a is of type int[int*]
writefln("%d", typeof('c').sizeof); // prints 1
double c = cast(typeof(1.0))j; // cast j to double
}
--------------------
$(P
$(I Expression) is not evaluated, just the type of it is
generated:
)
--------------------
void func()
{
int i = 1;
typeof(++i) j; // j is declared to be an int, i is not incremented
writefln("%d", i); // prints 1
}
--------------------
$(P There are three special cases: )
$(OL
$(LI $(D typeof(this)) will generate the type of what $(D this)
would be in a non-static member function, even if not in a member
function.
)
$(LI Analogously, $(D typeof(super)) will generate the type of what
$(D super) would be in a non-static member function.
)
$(LI $(D typeof(return)) will, when inside a function scope,
give the return type of that function.
)
)
--------------------
class A { }
class B : A
{
typeof(this) x; // x is declared to be a B
typeof(super) y; // y is declared to be an A
}
struct C
{
static typeof(this) z; // z is declared to be a C
typeof(super) q; // error, no super struct for C
}
typeof(this) r; // error, no enclosing struct or class
--------------------
$(P If the expression is a $(DDSUBLINK function, property-functions,
Property Function), $(D typeof) gives its return type.
)
--------------------
struct S
{
@property int foo() { return 1; }
}
typeof(S.foo) n; // n is declared to be an int
--------------------
$(P
Where $(I Typeof) is most useful is in writing generic
template code.
)
$(H3 Void Initializations)
$(GRAMMAR
$(GNAME VoidInitializer):
$(D void)
)
$(P Normally, variables are initialized either with an explicit
$(I 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.
)
-------------------------
void foo()
{
int x = void;
writeln(x); // will print garbage
}
-------------------------
$(P Therefore, one should only use $(D void) initializers as a
last resort when optimizing critical code.
)
$(H3 Global and Static Initializers)
$(P The $(GLINK Initializer) for a global or static variable must be
evaluatable at compile time.
Whether some pointers can be initialized with the addresses of other
functions or data is implementation defined.
Runtime initialization can be done with static constructors.
)
$(H3 Type Qualifiers vs. Storage Classes)
$(P D draws a distinction between a type qualifer and a storage class.)
$(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 type 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. One example is $(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.
}
--------
--------
// 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(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 Due to the fact that some keywords, such as $(D const), can be used
both as a type qualifier and a storage class, it may sometimes result
in ambiguous-looking code:)
--------
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() { return 1; }
}
--------
$(P To avoid such confusion, it is recommended that type qualifier
syntax with parentheses always be used for return types, and that
function storage classes 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; }
}
--------
)
Macros:
TITLE=Declarations
WIKI=Declaration
ASSIGNEXPRESSION=$(GLINK2 expression, AssignExpression)
EXPRESSION=$(GLINK2 expression, Expression)
VEXPRESSION=$(ASSIGNEXPRESSION)
_=