forked from dlang/dlang.org
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodule.dd
474 lines (368 loc) · 11.6 KB
/
module.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
Ddoc
$(SPEC_S Modules,
$(GRAMMAR
$(GNAME Module):
$(GLINK ModuleDeclaration) $(GLINK DeclDefs)
$(GLINK DeclDefs)
$(GNAME DeclDefs):
$(GLINK DeclDef)
$(GLINK DeclDef) $(I DeclDefs)
$(GNAME DeclDef):
$(GLINK2 attribute, AttributeSpecifier)
$(GLINK ImportDeclaration)
$(GLINK2 enum, EnumDeclaration)
$(GLINK2 class, ClassDeclaration)
$(GLINK2 interface, InterfaceDeclaration)
$(GLINK2 struct, AggregateDeclaration)
$(GLINK2 declaration, Declaration)
$(GLINK2 class, Constructor)
$(GLINK2 class, Destructor)
$(GLINK2 unittest, UnitTest)
$(GLINK2 class, StaticConstructor)
$(GLINK2 class, StaticDestructor)
$(V2
$(GLINK2 class, SharedStaticConstructor)
$(GLINK2 class, SharedStaticDestructor)
) $(GLINK2 version, ConditionalDeclaration)
$(GLINK2 version, DebugSpecification)
$(GLINK2 version, VersionSpecification)
$(GLINK2 version, StaticAssert)
$(GLINK2 template, TemplateDeclaration)
$(GLINK2 template-mixin, TemplateMixin)
$(GLINK MixinDeclaration)
$(B ;)
)
$(P Modules have a one-to-one correspondence with source files.
The module name is the file name with the path and extension
stripped off.
)
$(P Modules automatically provide a namespace scope for their contents.
Modules superficially resemble classes, but differ in that:
)
$(UL
$(LI There's only one instance of each module, and it is
statically allocated.)
$(LI There is no virtual table.)
$(LI Modules do not inherit, they have no super modules, etc.)
$(LI Only one module per file.)
$(LI Module symbols can be imported.)
$(LI Modules are always compiled at global scope, and are unaffected
by surrounding attributes or other modifiers.)
)
$(P Modules can be grouped together in hierarchies called $(I packages).
)
$(P Modules offer several guarantees:)
$(UL
$(LI The order in which modules are imported does not affect the
semantics.)
$(LI The semantics of a module are not affected by what imports
it.)
$(LI If a module C imports modules A and B, any modifications to B
will not silently change code in C that is dependent on A.)
)
<h3>Module Declaration</h3>
$(P The $(I ModuleDeclaration) sets the name of the module and what
package it belongs to. If absent, the module name is taken to be the
same name (stripped of path and extension) of the source file name.
)
$(GRAMMAR
$(GNAME ModuleDeclaration):
$(B module) $(I ModuleFullyQualifiedName) $(B ;)
$(GNAME ModuleFullyQualifiedName):
$(I ModuleName)
$(I Packages) $(B .) $(I ModuleName)
$(GNAME ModuleName):
$(I Identifier)
$(GNAME Packages):
$(I PackageName)
$(I Packages) $(B .) $(I PackageName)
$(GNAME PackageName):
$(I Identifier)
)
$(P The $(I Identifiers) preceding the rightmost are the $(I Packages)
that the module is in. The packages correspond to directory names in
the source file path.
Package names cannot be keywords, hence the corresponding
directory names cannot be keywords, either.
)
$(P If present, the $(I ModuleDeclaration) appears syntactically first
in the source file, and there can be only one per source file.
)
$(P Example:)
---------
module c.stdio; // this is module $(B stdio) in the $(B c) package
---------
$(P By convention, package and module names are all lower case. This is
because those names have a one-to-one correspondence with the operating
system's directory and file names, and many file systems
are not case sensitive. All lower case package and module names will
minimize problems moving projects between dissimilar file systems.
)
<h2><a name="ImportDeclaration">Import Declaration</a></h2>
$(P
Symbols from one module are made available in another module
by using the $(I ImportDeclaration):
)
$(GRAMMAR
$(GNAME ImportDeclaration):
$(B import) $(I ImportList) $(B ;)
$(B static import) $(I ImportList) $(B ;)
$(GNAME ImportList):
$(I Import)
$(I ImportBindings)
$(I Import) $(B ,) $(I ImportList)
$(GNAME Import):
$(I ModuleFullyQualifiedName)
$(I ModuleAliasIdentifier) $(B =) $(I ModuleFullyQualifiedName)
$(GNAME ImportBindings):
$(I Import) $(B :) $(I ImportBindList)
$(GNAME ImportBindList):
$(I ImportBind)
$(I ImportBind) $(B ,) $(I ImportBindList)
$(GNAME ImportBind):
$(I Identifier)
$(I Identifier) = $(I Identifier)
$(GNAME ModuleAliasIdentifier):
$(I Identifier)
)
$(P There are several forms of the $(I ImportDeclaration),
from generalized to fine-grained importing.)
$(P The order in which $(I ImportDeclaration)s occur has no
significance.)
$(P $(I ModuleFullyQualifiedName)s in the $(I ImportDeclaration) must be
fully qualified
with whatever packages they are in. They are not considered to
be relative to the module that imports them.)
<h3>Basic Imports</h3>
$(P The simplest form of importing is to just list the
modules being imported:)
---------
import std.stdio; // import module $(B stdio) from the $(B std) package
import foo, bar; // import modules $(B foo) and $(B bar)
void main()
{
writefln("hello!\n"); // calls std.stdio.writefln
}
---------
$(P How basic imports work is that first a name is searched for in the
current namespace. If it is not found, then it is looked for in the
imports.
If it is found uniquely among the imports, then that is used. If it is
in more than one import, an error occurs.
)
---
module A;
void foo();
void bar();
---
---
module B;
void foo();
void bar();
---
---
module C;
import A;
void foo();
void test()
{ foo(); // C.foo() is called, it is found before imports are searched
bar(); // A.bar() is called, since imports are searched
}
---
---
module D;
import A;
import B;
void test()
{ foo(); // error, A.foo() or B.foo() ?
A.foo(); // ok, call A.foo()
B.foo(); // ok, call B.foo()
}
---
---
module E;
import A;
import B;
alias B.foo foo;
void test()
{ foo(); // call B.foo()
A.foo(); // call A.foo()
B.foo(); // call B.foo()
}
---
<h3>Public Imports</h3>
$(P By default, imports are $(I private). This means that
if module A imports module B, and module B imports module
C, then C's names are not searched for. An import can
be specifically declared $(I public), when it will be
treated as if any imports of the module with the $(I ImportDeclaration)
also import the public imported modules.
)
---
module A;
void foo() { }
---
---
module B;
void bar() { }
---
---
module C;
import A;
public import B;
...
foo(); // call A.foo()
bar(); // calls B.bar()
---
---
module D;
import C;
...
foo(); // error, foo() is undefined
bar(); // ok, calls B.bar()
---
<h3>Static Imports</h3>
$(P Basic imports work well for programs with relatively few modules
and imports. If there are a lot of imports, name collisions
can start occurring between the names in the various imported modules.
One way to stop this is by using static imports.
A static import requires one to use a fully qualified name
to reference the module's names:
)
---
static import std.stdio;
void main()
{
writefln("hello!"); // error, writefln is undefined
std.stdio.writefln("hello!"); // ok, writefln is fully qualified
}
---
<h3>Renamed Imports</h3>
$(P A local name for an import can be given, through which
all references to the module's symbols must be qualified
with:)
---
import io = std.stdio;
void main()
{
io.writefln("hello!"); // ok, calls std.stdio.writefln
std.stdio.writefln("hello!"); // error, std is undefined
writefln("hello!"); // error, writefln is undefined
}
---
$(P Renamed imports are handy when dealing with
very long import names.)
<h3>Selective Imports</h3>
$(P Specific symbols can be exclusively imported from
a module and bound into the current namespace:)
---
import std.stdio : writefln, foo = writef;
void main()
{
std.stdio.writefln("hello!"); // error, std is undefined
writefln("hello!"); // ok, writefln bound into current namespace
writef("world"); // error, writef is undefined
foo("world"); // ok, calls std.stdio.writef()
fwritefln(stdout, "abc"); // error, fwritefln undefined
}
---
$(P $(B static) cannot be used with selective imports.)
<h3>Renamed and Selective Imports</h3>
$(P When renaming and selective importing are combined:)
------------
import io = std.stdio : foo = writefln;
void main()
{
writefln("bar"); // error, writefln is undefined
std.stdio.foo("bar"); // error, foo is bound into current namespace
std.stdio.writefln("bar"); // error, std is undefined
foo("bar"); // ok, foo is bound into current namespace,
// FQN not required
io.writefln("bar"); // ok, io=std.stdio bound the name io in
// the current namespace to refer to the entire module
io.foo("bar"); // error, foo is bound into current namespace,
// foo is not a member of io
--------------
<h3>Module Scope Operator</h3>
Sometimes, it's necessary to override the usual lexical scoping rules
to access a name hidden by a local name. This is done with the
global scope operator, which is a leading $(SINGLEQUOTE .):
---------
int x;
int foo(int x)
{
if (y)
return x; // returns foo.x, not global x
else
return .x; // returns global x
}
---------
The leading $(SINGLEQUOTE .) means look up the name at the module scope level.
<a name="staticorder"><h2>Static Construction and Destruction</h2></a>
$(P Static constructors are code that gets executed to initialize
a module or a class before the main() function gets called.
Static destructors are code that gets executed after the main()
function returns, and are normally used for releasing
system resources.)
$(P There can be multiple static constructors and static destructors
within one module. The static constructors are run in lexical order,
the static destructors are run in reverse lexical order.)
$(V2
$(P Static constructors and static destructors run on thread local
data, and are run whenever threads are created or destroyed.)
$(P Shared static constructors and shared static destructors are run
on global shared data, and constructors are run once on program startup
and destructors are run once on program termination.
)
)
<h3>Order of Static Construction</h3>
$(V2
$(P Shared static constructors on all modules are run before any static
constructors.
)
)
$(P The order of static initialization is implicitly determined by
the $(I import) declarations in each module. Each module is
assumed to depend on any imported modules being statically
constructed first.
Other than following that rule, there is no imposed order
on executing the module static constructors.
)
$(P Cycles (circular dependencies) in the import declarations are
allowed as long as not both of the modules contain static constructors
or static destructors. Violation of this rule will result
in a runtime exception.
)
<h3>Order of Static Construction within a Module</h3>
Within a module, the static construction occurs in the lexical
order in which they appear.
<h3>Order of Static Destruction</h3>
$(P It is defined to be exactly the reverse order that static
construction was performed in. Static destructors for individual
modules will only be run if the corresponding static constructor
successfully completed.
)
$(V2
$(P Shared static destructors are executed after static destructors.
)
)
<h3>Order of Unit tests</h3>
Unit tests are run in the lexical order in which they appear
within a module.
<h2>$(LNAME2 MixinDeclaration, Mixin Declaration)</h2>
$(GRAMMAR
$(GNAME MixinDeclaration):
$(B mixin) $(B $(LPAREN)) $(ASSIGNEXPRESSION) $(B $(RPAREN)) $(B ;)
)
$(P The $(ASSIGNEXPRESSION)
must evaluate at compile time
to a constant string.
The text contents of the string must be compilable as a valid
$(GLINK DeclDefs), and is compiled as such.
)
)
Macros:
TITLE=Modules
WIKI=Module
CATEGORY_SPEC=$0
FOO=