forked from dlang/dlang.org
-
Notifications
You must be signed in to change notification settings - Fork 4
/
module.dd
510 lines (397 loc) · 15.5 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
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
Ddoc
$(SPEC_S モジュール,
$(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, TemplateMixinDeclaration)
$(GLINK2 template-mixin, TemplateMixin)
$(GLINK MixinDeclaration)
$(B ;)
)
$(P モジュールはソースファイルと1対1に対応します。
モジュール名は、
ソースファイル名からパスと拡張子を除いたものになります。
)
$(P モジュールは自動で、その中身をスコープとする名前空間となります。
モジュールは表面的にはクラスと似たところがありますが、別のものです:
)
$(UL
$(LI モジュール毎にインスタンスは1つだけで、
静的に割り当てられます。)
$(LI 仮想関数テーブルを持ちません。)
$(LI モジュールには継承や親モジュールといった概念がありません。)
$(LI 1つのファイルには1つだけモジュールが対応します。)
$(LI モジュール内のシンボルはimportできます。)
$(LI モジュールは常にグローバルスコープでコンパイルされ、
周りで宣言された属性に影響を受けることなどはありません。)
)
$(P モジュールは、$(I packages) と呼ばれる階層にまとめることができます。
)
$(P モジュールは数々の保証を提供します:)
$(UL
$(LI モジュールを import
する順序がセマンティクスに影響することはありません。)
$(LI どこから import されるかによって、
そのモジュールのセマンティクスが変わることもありません。)
$(LI モジュールが C がモジュール A と B をimportしてるときに、Bに対する変更によって、
Aに依存するC内のコードが勝手に変更されることはありません。)
)
<h3>モジュール宣言</h3>
$(P $(I ModuleDeclaration) では、モジュールの名前と、
属するパッケージを指定します。もし宣言が存在しなければ、
ソースファイル名と同じ名前(パスと拡張子は除かれる)が使用されます。
)
$(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 右端の一個前にある $(I Identifiers) は、
モジュールが属する $(I パッケージ) を指します。
パッケージはソースファイルの置かれているディレクトリに対応します。
予約語をパッケージ名にすることはできません。
従って、予約語を対応するディレクトリ名に使うこともできません。
)
$(P もし $(I ModuleDeclaration) を書くならば、
ソースファイルの先頭に、一個だけ書く必要があります。
)
$(P 例:)
---------
module c.stdio; // これはモジュール $(B stdio) で、パッケージ $(B c) に属します
---------
$(P 慣習として、パッケージ名とモジュール名は全て小文字で書きます。
この名前はOSのファイル名やディレクトリ名に対応していて、
多くのファイルシステムでは大文字小文字を区別しないからです。
全て小文字にすると決めておくことで、
プロジェクトを別のファイルシステムへ持っていったときの問題が少なくなります。
)
<h2><a name="ImportDeclaration">import 宣言</a></h2>
$(P
テキストをそのまま#includeするのではなく、Dでは、
$(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 $(I ImportDeclaration) には、一般化されたものからより粒度を細かくしたものまで、
いくつか種類があります。)
$(P $(I ImportDeclaration)
の順番は特に意味を持ちません。)
$(P $(I ImportDeclaration) の $(I ModuleFullyQualifiedName) は、
どのパッケージに含まれているかにかかわらず、
完全修飾が必要です。
import元モジュールからの相対パスの考慮などはなされません。)
<h3>基本 import (Basic Import)</h3>
$(P 一番シンプルなimport文は、
単にimportしたいモジュールを列挙します:)
---------
import std.stdio; // モジュール $(B stdio) を $(B std) パッケージからimport
import foo, bar; // モジュール $(B foo) と $(B bar) をimport
void main()
{
writefln("hello!\n"); // std.stdio.writefln を呼び出す
}
---------
$(P 前がカレントの名前空間から見つからなかった場合に、
import
したモジュールから名前が探索されます。
import中で見つかった名前が唯一だった場合は、それが採用されます。
複数見つかった場合はエラーになります。
)
---
module A;
void foo();
void bar();
---
---
module B;
void foo();
void bar();
---
---
module C;
import A;
void foo();
void test()
{ foo(); // C.foo() の呼び出し。importよりもカレント名前空間を先に探索する
bar(); // A.bar() の呼び出し。importが使われる
}
---
---
module D;
import A;
import B;
void test()
{ foo(); // エラー。A.foo() か B.foo() か曖昧
A.foo(); // ok, A.foo()
B.foo(); // ok, B.foo()
}
---
---
module E;
import A;
import B;
alias B.foo foo;
void test()
{ foo(); // B.foo() の呼び出し
A.foo(); // A.foo() の呼び出し
B.foo(); // B.foo() の呼び出し
}
---
<h3>公開 import (Public Import)</h3>
$(P デフォルトでは、import は $(I private) です。これは例えば
モジュール A がモジュール B を、モジュール B はモジュール
C をimportしていた場合、Cの名前はAでは探索されないということです。ただし、
import を特別に $(I public) と宣言すると、その import
が取り込むモジュール内の全ての名前が、
現在のモジュールを外からimportするモジュールにも見えるようになります。
)
---
module A;
void foo() { }
---
---
module B;
void bar() { }
---
---
module C;
import A;
public import B;
...
foo(); // A.foo() の呼び出し
bar(); // B.bar() の呼び出し
---
---
module D;
import C;
...
foo(); // foo() は未定義
bar(); // ok, B.bar() の呼び出し
---
<h3>静的 import (Static Import)</h3>
$(P 基本importは、比較的少なめのモジュールとimportで成り立っているプログラムでは
うまく働きます。しかしimportの数が増えてくると、
多数のモジュールをimportしたことによる名前の衝突が起こり始めます。
これを避ける手段のひとつが、static importです。
static import した名前は、
使うときには完全修飾しなければいけません:
)
---
static import std.stdio;
void main()
{
writefln("hello!"); // エラー。writefln は未定義
std.stdio.writefln("hello!"); // ok。writefln は完全修飾されている
}
---
<h3>改名 import (Renamed Import)</h3>
$(P importするモジュールにローカルな名前を与えて、
その名前で修飾したアクセスを
強制することができます:)
---
import io = std.stdio;
void main()
{
io.writefln("hello!"); // ok。std.stdio.writefln の呼び出し
std.stdio.writefln("hello!"); // エラー。std は未定義
writefln("hello!"); // エラー。writefln は未定義
}
---
$(P 改名importは、
とても長いモジュール名を扱うのに便利です。)
<h3>選択 import (Selective Import)</h3>
$(P モジュールから一部のシンボルだけをimportして、
現在の名前空間で束縛することができます:)
---
import std.stdio : writefln, foo = writef;
void main()
{
std.stdio.writefln("hello!"); // エラー。std は未定義
writefln("hello!"); // ok。writefln はカレントの名前空間で束縛されている
writef("world"); // エラー。writef は未定義
foo("world"); // ok。std.stdio.writef() の呼び出し
fwritefln(stdout, "abc"); // エラー。fwritefln は未定義
}
---
$(P $(B static) は選択importに対しては指定できません。)
<h3>改名選択 import</h3>
$(P 改名importと選択importを組み合わせた例です:)
------------
import io = std.stdio : foo = writefln;
void main()
{
writefln("bar"); // エラー。writefln は未定義。
std.stdio.foo("bar"); // エラー。foo は現在の名前空間で束縛されている。
std.stdio.writefln("bar"); // エラー。std は未定義。
foo("bar"); // ok。foo は現在の名前空間にある。
// 完全修飾名は不要。
io.writefln("bar"); // ok。io=std.stdio で、ioという名前が
// モジュール全体を指すよう導入されている。
io.foo("bar"); // エラー。
// foo は現在の名前空間にある io のメンバではない
--------------
<h3>スコープ限定 import (Scoped Import)</h3>
$(P import 宣言は任意のスコープで使用できます。例:)
--------------
void main() {
import std.stdio;
writeln("bar");
}
--------------
$(P このimportは、そのスコープ内での未解決シンボルを探すのに使われます。
importされたシンボルが、外部のスコープのシンボルを隠すことがあります。)
$(P 関数スコープでは、import 宣言がソースコード中で現れた箇所より下でのみ、
import されたシンボルが見えるようになります。
言い方を変えると、関数スコープでの import
は前方参照できません。
)
--------------
void main() {
void writeln(string) {}
void foo() {
writeln("bar"); // main.writeln を呼ぶ
import std.stdio;
writeln("bar"); // std.stdio.writeln を呼ぶ
void writeln(string) {}
writeln("bar"); // main.foo.writeln を呼ぶ
}
writeln("bar"); // main.writeln を呼ぶ
std.stdio.writeln("bar"); // エラー。std は未定義
}
--------------
<h3>モジュールのスコープ解決演算子</h3>
ローカルの名前で隠されてしまったグローバルの識別子にアクセスしたいこと、
たまにあります。
そんな時は、Dではスコープ解決演算子 $(SINGLEQUOTE .) を使います:
---------
int x;
int foo(int x)
{
if (y)
return x; // グローバルの x ではなく foo.x を返す
else
return .x; // グローバルの x を返す
}
---------
名前の前に $(SINGLEQUOTE .) を付けると、モジュールスコープレベルで名前を探索することを意味します。
<a name="staticorder"><h2>静的コンストラクタ・デストラクタ</h2></a>
$(P 静的コンストラクタ、とは、main() 関数を呼び出すより前に
モジュールやクラスの初期化のために実行されるコードのことです。
静的デストラクタは、
逆にmain()の後に、モジュールが確保した
システムリソースの解放などのために実行されるコードです。)
$(P 一つのモジュールに複数の静的コンストラクタや静的デストラクタを定義することもできます。
静的コンストラクタはソースコードに書かれた順に上から実行され、
静的デストラクタはその逆順に実行されます。)
$(V2
$(P 静的コンストラクタや静的デストラクタはスレッドローカル記憶域に対して実行され、
スレッドが生成/破棄されるたびに実行されます。)
$(P shared静的コンストラクタやshared静的デストラクタはグローバル記憶域に対して実行され、
プログラムの開始時と終了時に、
一度ずつだけ実行されます。
)
)
<h3>静的コンストラクタの順序</h3>
$(V2
$(P 各モジュールのshared静的コンストラクタは、
どの静的コンストラクタよりも前に実行されます。
)
)
$(P 静的初期化の順序は、各モジュールに書かれた
$(I import) によって、暗黙のうちに決定されます。各モジュールは
import している他のモジュールに依存していると仮定し、
被依存モジュールを先に構築するように順序が決まります。
このルールに従ってさえいれば、
その他のモジュールどうしの実行順序については特に定まっていません。
)
$(P import宣言の循環(モジュールがお互いをimportしあう、循環依存)は、
どちらか一方が静的構築の不要なモジュールであれば、問題ありません。
双方とも静的構築が必要であった場合は、
実行時例外が発生します。
)
<h3>モジュール内部での静的構築の順序</h3>
モジュールの内部では、静的コンストラクタは、
ソースコードに書かれた順で上から実行されていきます。
<h3>静的デストラクタの順序</h3>
$(P 静的コンストラクタのちょうど逆の順番で実行される、
と定義されています。
モジュールの静的デストラクタコードは、
対応する静的コンストラクタが正しく完了していた場合にのみ実行されます。
)
$(V2
$(P shared静的デストラクタは全ての静的デストラクタより後に実行されます。
)
)
<h3>単体テストの順序</h3>
モジュールの内部では、単体テストは、
ソースコードに書かれた順で上から実行されていきます。
<h2>$(LNAME2 MixinDeclaration, mixin 宣言)</h2>
$(GRAMMAR
$(GNAME MixinDeclaration):
$(B mixin) $(B $(LPAREN)) $(ASSIGNEXPRESSION) $(B $(RPAREN)) $(B ;)
)
$(P $(ASSIGNEXPRESSION)
は、
コンパイル時定数へと評価される文字列である必要があります。
その文字列の内容は正当な
$(GLINK DeclDefs) としてコンパイルできるものでなければならず、その場合、その通りにコンパイルされます。
)
)
Macros:
TITLE=モジュール
WIKI=Module
CATEGORY_SPEC=$0
FOO=