forked from dlang/dlang.org
-
Notifications
You must be signed in to change notification settings - Fork 4
/
faq.dd
950 lines (717 loc) · 45 KB
/
faq.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
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
Ddoc
$(D_S $(TITLE),
$(P 何度も訊かれる質問が増えてきので、
FAQ を用意しました。)
$(P $(LINK2 http://www.digitalmars.com/d/1.0/faq.html, D 1.0 FAQ))
$(P $(LINK2 http://www.digitalmars.com/faq.html, C++ FAQ))
<h2>D 2.0 FAQ</h2>
$(UL
$(LI $(LINK2 features2.html, D 2.0 と D 1.0 の違いは?))
$(LI 「シンプルな言語」はどこに行っちゃったの)
$(REDO $(LI $(LINK2 cpp0x.html, C++0x に提案された機能に対する D 2.0 での対応は?)))
$(LI 他にどんなクールな機能が D 2.0 には予定されてるんだい?)
$(LI 僕が提案した最高の機能が無視されているのはなぜですか!)
$(LI なぜ const や immutable なんてものが必要?)
$(LI なぜ const や immutable なんていう $(I 名前) なの?)
$(LI immutable と マルチコア の関係を正確に述べてください)
$(LI OK、スレッド間の安全なデータ共有におけるimmutableの利点はわかった。でもそういう意味での情報量のないconstがなんで必要なの?)
$(LI なぜ D 2.0 では immutable 文字列が好まれるのか?)
$(LI D 2.0 に貢献したいです。どうすればいいでしょうか?)
$(ITEMR case_range, なぜ case range 式は
$(D case X..Y:) という構文にしないの?)
$(ITEMR shared_guarantees, shared が提供する保証は?)
$(ITEMR shared_synchronized, shared と同期の関係は?)
$(ITEMR shared_memory_barriers, shared とメモリバリアの関係は?)
$(ITEMR casting_to_shared, unshared から shared へのキャストはどういう意味論になる?)
$(ITEMR casting_from_shared, shared から unshared へのキャストはどういう意味論になる?)
$(ITEMR bss, なぜ大きな静的配列を使うとexeのファイルが増えるの?)
)
<h2>D 全般の FAQ</h2>
$(UL
$(LI $(LINK2 http://www.prowiki.org/wiki4d/wiki.cgi?FaqRoadmap, The D wiki FAQ page)
でもっと多くの質問への回答があります。)
$(LI $(LINK2 comparison.html, C++ に無くて D にあるものは?))
$(ITEMR q1, なぜ D という名前なのですか?)
$(ITEMR q1_1, D という名前は変えられないの?検索エンジンで探しにくい。)
$(LI $(LINK2 http://www.digitalmars.com/d/download.html, Dコンパイラはどこで手に入りますか?))
$(ITEMR q1_2, DはLinuxへ移植されていますか?)
$(ITEMR gdc, GNU版のDはありますか?)
$(ITEMR backend, ××というCPU向けの自作のDコンパイラを書くにはどうしたらよいですか?)
$(ITEMR gui, DのGUIライブラリはどこで入手できますか?)
$(ITEMR ide, DのIDEはどこで入手できますか?)
$(ITEMR q4, printf という [-放送禁止-] なものを残したのは何故ですか?)
$(ITEMR q5, D はオープンソースですか?)
$(ITEMR q5_2, 標準ライブラリが Boost ライセンスなのは何故?パブリックドメインにしないのですか?)
$(ITEMR q6, switch文がfall throughなのは何故ですか?)
$(ITEMR q7, JavaではなくDを選ぶ理由としては何があるでしょう?)
$(ITEMR q7_2, C++でも、文字列はSTLでサポートされているのですが…)
$(ITEMR q7_3, C++でも、ガベージコレクションはライブラリを使えば可能なのではないでしょうか?)
$(ITEMR q7_4, C++でも、単体テストはライブラリを使えば可能なのではないでしょうか?)
$(ITEMR q8, 移植性を重視した言語なのにasm文があるのは何故ですか?)
$(ITEMR real, 80bit実数型の利点は?)
$(ITEMR anonymous, D で無名構造体/共用体を使うには?)
$(ITEMR printf, 文字列に対して printf() を動作させるには?)
$(ITEMR nan, なぜ浮動小数点数は0ではなくNaNに初期化されるのですか?)
$(ITEMR assignmentoverloading, なぜ代入演算子のオーバーロードに対応していないのですか?)
$(ITEMR keys, $(SINGLEQUOTE ~) は私のキーボードにないのですが…)
$(ITEMR omf, Can I link in C object files created with another compiler?)
$(ITEMR regexp_literals, 正規表現リテラルを
/foo/g のような構文でサポートしないのはなぜですか?)
$(ITEMR dogfood, なぜDのフロントエンドはDではなくC++で書かれているのですか?)
$(ITEMR cpp_to_D, Digital Mars のプログラムを全てDで書き直したらどうでしょう?)
$(ITEMR foreach, どのような時にforよりもforeachループを使うとよいですか?)
$(ITEMR cpp_interface, Dに、CとのインターフェイスはあってもC++とのは無いのは何故?)
$(ITEMR reference-counting, なぜDはガベージコレクションに参照カウント方式を使わないのですか?)
$(ITEMR gc_1, ガベージコレクションは遅くて予測不能なんでしょ?)
$(ITEMR pure, 十分に賢いコンパイラなら、関数がpureかどうか自動的に判別できるんじゃないの?)
$(ITEMR minimum precision, $(D cast(float)) がその通りに動かないなら何故サポートしているの?)
$(ITEMR nested_forward_references, ネストした関数が前方参照できないのはどうして?)
)
$(ITEM case_range, なぜ case range 式は
$(D case X..Y:) という構文にしないの?)
$(P $(LINK2 statement.html#CaseRangeStatement, case range statement) を参照して下さい。)
$(P この構文にすると、.. の使い道は以下の3つになります:
$(OL
$(LI $(D case X..Y:))
$(LI $(D foreach(e; X..Y)))
$(LI $(D array[X..Y]))
)
最初のケース (1) だけが、(2) や (3) と $(B 非常に異なった) 意味を持っています。
(1) は区間に Y を含みますが、(2) と (3) は Y を含みません。
非常に異なった意味を持つということは、区別できる異なった構文を持つべきであるということを意味します。
)
$(ITEM shared_guarantees, shared が提供する保証は?)
$(P shared は、複数のスレッドがそのデータにアクセスしうることを意味します。
保証されるのは、sharedでなく、immutableでもないデータは、カレントスレッドからしか見えない、ということです。
)
$(ITEM shared_synchronized, shared と同期の関係は?)
$(P shared データのみが同期できます。
他の、スレッドローカルデータを同期する意味はありません。
)
$(ITEM shared_memory_barriers, shared とメモリバリアの関係は?)
$(P sharedデータへの読み書きの際には、逐次一貫性を保証するメモリバリアが生成されます
(未実装です)。
)
$(ITEM casting_to_shared, unshared から shared へのキャストはどういう意味論になる?)
$(P そのデータへの他のunshared参照がないことが確実な場合のみ意味のある操作になります。
)
$(ITEM casting_from_shared, shared から unshared へのキャストはどういう意味論になる?)
$(P そのデータへの他のshared参照がないことが確実な場合のみ意味のある操作になります。
)
$(ITEM bss, なぜ大きな静的配列を使うとexeのファイルが増えるの?)
$(P このような宣言があると:)
---
char[1024 * 1024] arr;
---
$(P 実行ファイルのサイズは1MB増えます。
Cでは、$(CODE arr) がBSSセグメントに格納されるのでこれは起こりませんでした。
Dが $(CODE arr) BSSセグメントに格納しない理由は:
)
$(UL
$(LI $(CODE char) 型が、0 ではなく、0xFF に初期化されるため。
非ゼロのデータはBSSに配置することはできません。)
$(LI 静的に割り当てたデータはスレッドローカル記憶域に配置されるため。
BSSはスレッドローカルでは無く、BSSに相当するスレッドローカル領域はありません。)
)
$(P 以下のように書くとBSSに配置されます:)
---
__gshared byte[1024 * 1024] arr;
---
$(P $(CODE byte) の初期値は 0 で、$(CODE __gshared)
はデータをグローバルに割り当てるためです。)
$(P $(CODE float), $(CODE double), $(CODE real)
の静的配列にも同様の問題があります。これらの型も、0 ではなく NaN (Not A Number) 値に初期化されるためです。
)
$(P この問題に対処する一番簡単な方法は、
配列を静的にではなく実行時に動的に割り当てることです。
)
$(ITEM q1, なぜ D という名前なのですか?)
$(P 元々は プログラミング言語 Mars という名前でした。けれど友人が
D と呼び続けたので、私も影響されて D と呼ぶようになったのです。
C の後継の D言語、という案は、
少なくとも1988年のこの
$(LINK2 http://groups.google.com/group/comp.lang.c/browse_thread/thread/cb4b868fab477b61/d4b5407644d16806, スレッド) までさかのぼります。
)
$(ITEM q1_1, D という名前は変えられないの?検索エンジンで探しにくい。)
$(P 変えられません。検索しにくくてストレスが溜まる、という点は承知していますが、
もう現時点となっては名前を変えるには遅すぎるところまで来てしまいました。検索語としては "dlang", "d programming",
"d language", "d programming language" などを使うことをお勧めします。
こうすることでずっと良い検索結果が得られます。
)
$(P 公開されている D のコードの多くは "// Written in the D programming
language" をコメントの最初に含んでいます。
)
$(ITEM q1_2, DはLinuxへ移植されていますか?)
$(P はい。DigitalMarsのDコンパイラには $(LINK2 dmd-linux.html, Linux版) があります。
)
$(ITEM gdc, GNU版のDはありますか?)
$(P はい、
$(LINK2 http://bitbucket.org/goshawk/gdc/wiki/Home, gdc - the D frontend with GCC) です。
)
$(ITEM backend, ××というCPU向けの自作のDコンパイラを書くにはどうしたらよいですか?)
$(P Burton Radons が
$(LINK2 http://www.opend.org/dli/DLinux.html, バックエンド)
を公開しています。参考となるでしょう。
)
$(ITEM gui, DのGUIライブラリはどこで入手できますか?)
$(P D からは C の関数を呼び出せますので、Cのインターフェイスをもった
GUI ライブラリなら、全てDからも使えます。D言語用の様々なGUIライブラリや移植版が、
$(LINK2 http://www.prowiki.org/wiki4d/wiki.cgi?GuiLibraries, the D wiki) で紹介されています。
)
$(ITEM ide, DのIDEはどこで入手できますか?)
$(P D 対応のIDEの一覧が
$(LINK2 http://prowiki.org/wiki4d/wiki.cgi?EditorSupport, the D wiki) にあります。
)
$(ITEM q4, D になぜ printf が残っているのですか?)
$(P $(LINK2 http://www.digitalmars.com/rtl/stdio.html#printf, printf)
は実際はDの一部ではなく、
しかしDからアクセスできるCの標準ライブラリです。
D の標準ライブラリは
$(LINK2 http://dlang.org/phobos/std_stdio.html#writefln, std.stdio.writefln),
を含んでいて、これは $(LINK2 http://www.digitalmars.com/rtl/stdio.html#printf, printf)
並に強力でしかも使いやすくなっています。
)
$(ITEM q5, D はオープンソースですか?)
$(P D の $(B dmd) コンパイラのフロントエンドはオープンソースです。
dmd のバックエンドは Symantec からライセンスされていて、
GPL 等のオープンソースライセンスとは互換性がありません。
しかしながら、完全なソースコードが
$(LINK2 http://www.digitalmars.com/d/download.html, コンパイラ)
に附属し、開発は全て公開されて
$(LINK2 https://github.com/D-Programming-Language/dmd, github) で行われています。
DMD のフロントエンドに GCC や LLVM
のオープンソースのバックエンドを合わせたコンパイラもあります。
ランタイムライブラリは完全にオープンソースで、
$(LINK2 http://boost.org/LICENSE_1_0.txt, Boost License 1.0) でライセンスされています。
$(B gdc) と $(B ldc) は完全にオープンソースな D コンパイラです。
)
$(ITEM q5_2, 標準ライブラリが Boost ライセンスなのは何故?パブリックドメインにしないのですか?)
$(P ほとんどの地域の司法にはパブリックドメインという概念がありますが、
そうでない国 (例えば日本) もあります。
$(LINK2 http://boost.org/LICENSE_1_0.txt, Boost License)
はこの問題を回避しています。 このライセンスが選ばれた理由は、
多くのオープンソースライセンスと違って、
バイナリ形式の配布にライセンス文を含めることを要求していないからです。
)
$(ITEM q6, switch文がfall throughなのは何故ですか?)
$(P 沢山の人に、switch 文のcaseとcaseの間には必ずbreakが入る、
という仕様にならないかと要求されました。C の、いわゆる
"fall through" は沢山のバグの原因となってきたからです。
)
$(P D2 では、暗黙の fall throught は禁止されました。fall throught したいときは
$(LINK2 statement.html#GotoStatement, goto case;) を挿入して、
その意思を明示する必要があります。
)
$(P これに加えてさらに $(B break)
文が暗黙の動作になるべきという提案もありました。
Dでこれを変えなかった理由は、整数の昇格や演算子の優先順位を同じにしたのと、
同様の理由 - Cとして読めるコードはCと同様に振る舞うべき - です。
潜在的に違う意味をもっていたりしたら、
余計わかりにくいバグを生むでしょうから。
)
$(ITEM q7, JavaではなくDを選ぶ理由としては何があるでしょう?)
$(P D と Java では、目的も哲学も実現も異なっています。この
$(LINK2 comparison.html, 比較) をご覧下さい。
)
$(P Java は 'write once, run everywhere' を目的に設計されました。対して D は、
効率的なネイティブアプリを書くために設計されています。DもJavaも
ガベージコレクションは善で多重継承は悪で… というあたりで共通点はありますが、
目的の違いから、言語自体の感じも大きく違うものになっています。
)
$(ITEM q7_2, C++では、文字列はSTLでサポートされているんですが…)
$(P C++の標準ライブラリには、
文字列や動的配列に連想配列、
境界チェック付き配列や複素数などが存在します。
)
$(P もちろん、これらの機能は全てライブラリや、
何らかのコーディング方針を守ることなので実現できます。
しかしそれを言ったら、Cでオブジェクト指向だってできるのです
(実際に目にしたことがあります)。どんな簡単な BASIC
インタプリタでもサポートしている文字列というものために、
巨大で複雑な機構が必要というのはどうも不釣り合いです。
STLの文字列型は、実装に二千行以上のコードが費やされ、
高度なtemplateの機能を縦横に使っています。
これら全てが正しく動いているということをどれほど確信できるでしょう?
もしまずい点があったらどうやってそれを直すのでしょう。
使っていてコンパイルエラーが出たときの猛烈に読みにくいエラーメッセージは
どうすればよいのでしょう?自分の使い方が正しい(メモリリークが起きないとか…)
ことをどうやって確かめればよいでしょうか?
)
$(P Dの文字列実装は簡単で、直接的です。どう使えばいいか迷うようなことは
ほとんどありませんし、メモリリークの心配もありません。
エラーメッセージは的を射ていて、期待通りに動作しているかどうかは
見ればすぐにわかります。
)
$(ITEM q7_3, C++でも、ガベージコレクションはライブラリを使えば可能なのではないでしょうか?)
はい、私も使っています。しかし、言語の一部でないという特性上、
これを使うにはいくつか制約が生じます。また一般のC++プログラマにとっては、
C++でgcを使うという選択肢はないようです。
Dのように言語内にGCを組み込むのは、
日々のプログラミングにとってとても実用的です。
<p>
あまり先進的なことをしなければ、GCの実装は難しくありません。
簡単なものでも言語は100%動くという点で、より高度なGCを書くというのは、
より高度な最適化ルーチンを書く、ということに似ています。
規格をどの程度実装しているかというような点ではなく、
どの程度良いコードを生成するか、という点で複数の実装を比べられる方が、
プログラミングコミュニティにとってより良い状態です。
$(ITEM q7_4, C++でも、単体テストはライブラリを使えば可能なのではないでしょうか?)
もちろん。そのライブラリを使ってみて、Dと比べてみてください。
言語に組み込まれているというのがどんなに便利か、
すぐに明らかに感じるでしょう。
$(ITEM q8, 移植性を重視した言語なのにasm文があるのは何故ですか?)
asm文は、Dの関数内に直接アセンブリのコードを書き込むことを可能にします。
アセンブラのコードは自明に移植性のないものとなりますが、しかし、
システムアプリの開発には非常に便利なものです。システムアプリは
大なり小なりシステム依存のコードを含むことになるので、インラインアセンブラは
大した問題にはなりません。インラインアセンブラは、CPUの特殊命令や
フラグビットへのアクセスによって、特別な処理の場合や、
限界までコードを最適化したいときに役立ちます。
<p>
Cコンパイラがインラインアセンブラ機能を持つ前は、
私は外部のアセンブラを使っていました。アセンブラは
沢山の、本当に沢山のバージョンがあって、各バージョン毎に微妙に
構文が違っていたりバグがあったりコマンドラインの文法まで
変わっていたりして、非常に残念な思いをしました。
つまり、アセンブラの必要なコードは、ユーザーには安心してビルドはできなかったのです。
インラインアセンブラができてからは、そんなことはなくなりました。
$(ITEM real, 80bit実数型の利点は?)
有効桁数を増やせば増やすだけ、
正確に浮動小数点数の計算ができます。
これは特に大きな数と小さな数を足すときに顕著です。この話題については、
Intel の FPU をデザインした Kahan博士による、説得力のある
<a href="http://http.cs.berkeley.edu/~wkahan/JAVAhurt.pdf">論文</a>
があります。
$(ITEM anonymous, D で無名構造体/共用体を使うには?)
-----------------------
import std.stdio;
struct Foo
{
union { int a; int b; }
struct { int c; int d; }
}
void main()
{
writefln(
"Foo.sizeof = %d, a.offset = %d, b.offset = %d, c.offset = %d, d.offset = %d",
Foo.sizeof,
Foo.a.offsetof,
Foo.b.offsetof,
Foo.c.offsetof,
Foo.d.offsetof);
}
-----------------------
$(ITEM printf, 文字列に対して printf() を動作させるには?)
Cでは、文字列をprintfするには通常、書式 $(B %s)
を使います:
$(CCODE
char s[8];
strcpy(s, "foo");
printf("string = '$(B %s)'\n", s);
)
D で次のようにこれを実行してみると:
---------------------------------
char[] s;
s = "foo";
printf("string = '$(B %s)'\n", s);
---------------------------------
大抵の場合、ゴミが表示されるかアクセス違反になります。
原因は、Cでは文字列は0終端であるためです。
$(B %s) fは 0 が現れるまで文字を出力しようとします。
Dでは、文字列は0終端ではなく、長さは別に保持された値で決定されます。
そこで、printfを文字列に使うには
書式 $(B %.*s) を使うことになります:
---------------------------------
char[] s;
s = "foo";
printf("string = '$(B %.*s)'\n", s);
---------------------------------
$(P 今度は期待したとおりに動作するでしょう。
しかし注意が必要なのは、printf の $(B %.*s) は、長さ分もしくは 0 が現れるまで
出力する、ということです。このため、中に0を含むDの文字列は、
最初の0までしか出力されません。
)
$(P もちろん、もっと簡単な解決策は D の文字列に対して正しく動作する $(B std.stdio.writefln)
を使うことです。
)
$(ITEM nan, なぜ浮動小数点数は0ではなくNaNに初期化されるのですか)
浮動小数点数は、明示的に初期化子が指定されていない限り、
NaN (Not A Number) へと初期化されます:
---------------------------------
double d; // d は double.nan に設定される
---------------------------------
NaNは、演算のオペランドに使われると常に結果もNaNになるという、
素晴らしい特徴を備えています。従って、
NaNが計算課程にひとたび現れると、
これは伝搬し、出力としてNaNが得られることになります。
このことは、出力でのNaNの出現は、
どこかで未初期化変数が使われていることの証拠となることを示しています。
<p>
仮に 0.0 が浮動小数点数のデフォルト初期化子であったならば、
その結果は出力からは簡単には気づけなくなり、
そのデフォルト初期化値が意図したものではなかったときでも、
そのバグが見過ごされてしまうかもしれません。
<p>
デフォルト初期化値は、有用な値であることは意図されていません。
バグの発見がその用途です。そして、NaNはこの役割を適切に果たしています。
<p>
しかし、初期化されていない変数は当然コンパイラが見つけて、
エラーメッセージを出せるのではないでしょうか?
ほとんどの場合確かにそれは可能ですが、常にではありません。この可能性は、
コンパイラ内部のデータフロー解析がどれだけ洗練されているかにかかっています。
それゆえ、そんな機能に頼るのは可搬性・信頼性に欠けます。
<p>
CPUがそう設計されたため、整数にはNaN値がありません。
そこで D では代わりに 0 を使います。
これは NaN のようなエラー検知には役立ちませんが、
少なくとも、意図しないデフォルト初期化に起因する結果は常に一定になり、
デバッグがより楽になります。
$(ITEM assignmentoverloading, なぜ代入演算子のオーバーロードに対応していないのですか?)
$(P 構造体に対する代入演算子のオーバーロードは
D 2.0 でサポートされました。)
$(ITEM keys, $(SINGLEQUOTE ~) は私のキーボードにないのですが…)
$(P PCのキーボードでは、[Alt]を押しながらテンキーの 1, 2, 6
を順に押してAltを離すと、
$(SINGLEQUOTE ~) が入力されます。
)
$(ITEM omf, 他のコンパイラで作ったCのオブジェクトファイルをリンクできますか?)
DMDはOMF形式 (Microsoft Object Module Format)
のオブジェクトファイルを生成しますが、他のコンパイラ、例えば VC++
はCOFF形式のオブジェクトファイルを生成します。
DMD の出力は、同じくOMF形式のオブジェクトファイルを生成する
DMC (Digital Mars C コンパイラ) と共に動作するように設計されています。
<p>
DMDの使うOMF形式は、かつてIntelが設計した形式に基づいて、Microsoft
が定義したものに基づいています。Microsoftはある時から、
OMFの使用をやめて新しく定義したCOFFのMicrosoft版を使うようになりましたが。
<p>
同じオブジェクトファイル形式を採用しているからと言って、その形式のCライブラリが
正しくリンクできて実行できるとは限りません。実際にはもっと様々な互換性が必要です -
例えば、呼び出し規約や、名前マングリング、コンパイラの補助関数、
細かい動作に関する暗黙の仮定など -。例えDMDがMicrosoftのCOFFを出力できたとしても、
VCで使うために作られテストされたオブジェクトファイルを、
そのまま正しくリンクして実行できる可能性はほとんどありません。
Microsoftのコンパイラが実際にOMFを出力していた頃から、
この手の問題は多数存在していました。
<p>
相異なるオブジェクトファイル形式の存在は、DMD
での動作がチェックされていないライブラリであることを示す役目を果たしています。
もしこうなっていなければ、リンクはどうにかできても、もっと見つけにくい問題の
素になってしまいます。あるコンパイラでビルドされたバイナリを、
別のベンダのコンパイラの出力と合わせて使えるようにするのは、
エキスパートの技が必要な作業なのです。
<p>
とは言えLinux版のDMDは、Linuxでの標準形式である ELF
形式のオブジェクトファイルを生成しますから、LinuxのCコンパイラとして標準的な
gcc とは特にうまく協調できるようになっています。
<p>
既存のCライブラリを使うことができる場合も一つだけあります。それは、
そのライブラリがCのABIインターフェイスに適合したDLLとして提供されている場合です。
この場合ライブラリのリンク可能部分は "インポートライブラリ" と呼ばれ、
Microsoft の COFF形式のインポートライブラリは、
<a href="http://www.digitalmars.com/ctg/coff2omf.html">coff2omf</a>
を使えば DMD の
OMF 形式へと正しく変換できます。
$(ITEM regexp_literals, 正規表現リテラルを
$(D /foo/g) のような構文でサポートしないのはなぜですか?)
$(P 理由は二つあります:
)
$(OL
$(LI / は除算トークンでもあるため、 $(D /foo/g) 構文を導入すると、
字句解析器と構文解析器を分離することが不可能になります。)
$(LI 現在、すでに3種類の文字列リテラルが存在し、正規表現リテラルを追加すると
さらに3種類増えることになります。これは、コンパイラやデバッグ情報、
ライブラリなど多くの部分に波及しますが、それだけの価値がある変更ではありません。)
)
$(ITEM dogfood, なぜDのフロントエンドはDではなくC++で書かれているのですか?)
$(P フロントエンドがC++なのは、既存のgccやdmdのバックエンドとの整合性を
とるためです。
他の既存のコンパイラバックエンドも多くはC++で書かれているので、
これは他のバックエンドへも簡単に移植できることにつながります。
$(LINK2 http://www.digitalmars.com/dscript/index.html, DMDScript)
の D による実装
($(LINK2 http://www.digitalmars.com/dscript/cppscript.html, C++版),
よりもパフォーマンスが優れています)
の存在は、
100% D でプロ品質のコンパイラを書くのに何の問題もないことを示しています。
)
$(ITEM cpp_to_D, Digital Mars のプログラムを全てDで書き直したらどうでしょう?)
$(P 複雑でデバッグ済みで既に完成しているアプリケーションをわざわざ他言語に
移植することにあまり利点はありません。新しい Digital Mars のアプリは
Dで実装されています。)
$(ITEM foreach, どのような時にforよりもforeachループを使うとよいですか?)
$(P どのような時にforよりもforeachループを使うとよいですか?
)
$(P foreachを使えば、プログラマが自分で考えなくても、
最適化のための選択を
コンパイラに全て任せることができます。
例えば -- ポインタと添字のどちらを使うか?
終了条件をキャッシュしておくべきか否か? ループを回すべきか否か?
これらの選択肢に対する最適解は自明ではありませんし、そもそもマシンによって
変わってきます。レジスタ割り当てなどと同じように、
こんな仕事はコンパイラに任せましょう。)
---
for (int i = 0; i < foo.length; i++)
---
や:
---
for (int i = 0; i < foo.length; ++i)
---
や:
---
for (T* p = &foo[0]; p < &foo[length]; p++)
---
や:
---
T* pend = &foo[length];
for (T* p = &foo[0]; p < pend; ++p)
---
や:
---
T* pend = &foo[length];
T* p = &foo[0];
if (p < pend)
{
do
{
...
} while (++p < pend);
}
---
や、もちろん、size_t を使うべきか int を使ったほうがいいのか?
---
for (size_t i = 0; i < foo.length; i++)
---
こういった選択はコンパイラに選ばせましょう!
---
foreach (v; foo)
...
---
$(P 型Tが何であるべきかすら考えなくていいことにも注目してください。
これによって、Tが変化したときのバグの原因が減ります。fooが配列なのか、
連想配列なのか、あるいは構造体やコレクションクラスなのかすら気にする必要はありません。
これによって、ありがちな終了条件まわりのバグも避けられます:)
---
for (int i = 0; i <= foo.length; i++)
---
$(P さらに、fooが関数呼び出しだった場合に一時変数を手で作る手間も
これによって回避できています。)
$(P forループを使う唯一の理由は、そのループが通常のループ形式に
合わない場合…つまり例えば
その場で終了条件が変化する場合…であるときのみです。)
$(ITEM cpp_interface, Dに、CとのインターフェイスはあってもC++とのは無いのは何故?)
$(V2
$(P D 2.0 には、制限された形ではありますが、
$(LINK2 cpp_interface.html, C++ とのインターフェイス) があります。
) 以下に、このインターフェイスが完全でない理由を挙げます:
)
$(P D の C++ に対するインターフェイスを作るのは
C++ のコンパイラを書くのとほとんど同じくらい複雑で、これは
Dを十分実装しやすい言語とするという目標と矛盾してしまいます。
既存のC++コードを元に開発を続けなければならない人は、残念ながら
C++から離れることはできないでしょう (D以外の言語であっても移ることは不可能です。))
$(P 変更できないC++のコードを任意にDから呼び出せるようにしようと思うと、
さまざまな困難が待ちかまえています。
以下のリストはもちろん完全ではなく、
いかに難しいかを示す例として挙げてあります。
)
$(OL
$(LI DのソースコードはUnicodeですが、C++はASCIIか、
あるいは指定されていません。これは文字列リテラルの内容に影響します。)
$(LI std::string はマルチバイトのUTFを適切に処理できません。)
$(LI C++のタグは個別の名前空間を持っていますが、Dにはありません。
従ってある種のリネームが必要になります。)
$(LI C++のコードはコンパイラの独自拡張に依存していることが多いです。)
$(LI C++ には名前空間があります。Dにはモジュールがあります。
この二つの対応関係は単純ではありません。)
$(LI C++ はソースコードを(プリプロセス後の)巨大なファイルと見なして処理します。
Dはモジュールとパッケージの階層として処理します。)
$(LI enumの名前スコープ規則が異なっています。)
$(LI C++のコードは、マクロをできるだけ使わないようにという長年の試みにもかかわらず、
マクロにマクロを重ねた層に依存しています。
Dには、トークン結合や
文字列化のようなマクロに対応するものがありません。)
$(LI マクロ名は #include を超えてグローバルなスコープを持ちますが、
巨大ソースファイルと見なすとローカルスコープです。)
$(LI C++ には多重継承や仮想継承があります。
Dにはありません。)
$(LI C++ はin,out,ref(inout)引数を区別しません。)
$(LI C++ の名前マングリング方式はコンパイラ毎に異なります。)
$(LI C++ は任意の型の例外(Objectの派生に限らない)
を送出する可能性があります。)
$(LI C++ には const と volatile によるオーバーロードがありますが、
D には const と immutable によるオーバーロードがあります。)
$(LI C++ の演算子オーバーロード方式はだいぶDと違っています。例えば、
operator[]() の左辺値と右辺値としてのオーバーロードは、
const によるオーバーロードとプロキシクラスを使って実現されます。)
$(LI C++ の例えば < の演算子オーバーロードは
完全に > と独立しています。)
$(LI C++ はクラスと構造体を区別しません。)
$(LI 仮想関数テーブルの位置とレイアウトは C++ と D とで異なります。)
$(LI RTTI の実現方式もまったく異なります。
C++にはclassinfoはありません。)
$(LI D には two phase lookup や Koenig (ADL) lookup
はありません。)
$(LI C++ はクラス同士を 'friend' で関連づけますが、D
ではパッケージとモジュールに基づいて行われます。)
$(LI C++ のクラスデザインは、明示的なメモリ割り当ての問題を解決することを
念頭においておこなわれがちですが、Dではそうではありません。)
$(LI D のテンプレートシステムはだいぶ違っています。)
$(LI C++ には '例外仕様' があります。)
$(LI C++ にはグローバルな演算子オーバーロードがあります。)
$(LI C++ の名前マングリングは、const と volatile
が型修飾子であることに依存しています。
一方で D の名前マングリングは const と immutable が型修飾子であることに依存しています。
また、D の const は C++ のそれと違い推移的なので、
D では mutable への const ポインタのようなものが表現できません。
)
)
$(P 問題の根底にあるのは、言語設計はその上で書かれるコードに影響する、
ということです。C++の言語設計はDにフィットしていません。
たとえ二者を自動的に繋ぐ方法を発見できたとしても、
その結果は左半分ホンダで右半分カマロのような大変なものになってしまうでしょう。
)
$(ITEM reference-counting, なぜDはガベージコレクションに参照カウント方式を使わないのですか?)
$(P 参照カウント方式には利点もありますが、
いくつか重大な欠点があります:
)
$(UL
$(LI 循環データ構造が解放されません)
$(LI ポインタのコピーのたびに毎回参照カウントの上げ下げが必要です。
単に関数に参照を渡すだけのときであっても。)
$(LI マルチスレッド環境では、カウントの上げ下げに同期処理まで必要です。)
$(LI メモリリークを避けるために、カウントを減らす例外ハンドラ (finally)
を挿入する必要があります。他の部分でどうがんばろうとも、
"オーバーヘッド無し例外" はありえないことになります。)
$(LI スライスや配列内部へのポインタに対応するには、あるいは同様に
非オブジェクトの任意のメモリ割り当てを参照カウントで管理するには、
独立した"ラッパー"オブジェクトを参照カウントしたいメモリ領域毎に
用意しなければなりません。これは本質的に、
必要なメモリ割り当て回数を倍増させます。)
$(LI ラッパオブジェクトが必要と言うことは、ポインタ経由のデータへの参照には、
常に2回ずつの参照外しが必要ということを意味します。)
$(LI コンパイラを調整してこれらすべてをプログラマから見えずに澄むようにしてしまうと、
Cとの綺麗なインターフェイスを整えるのが難しくなります。)
$(LI 典型的なケースでは総合的なメモリ消費はGCの方が大きくなりますが、
参照カウントはヒープを断片化させ、従って GC
以上にメモリを消費する可能性があります。)
$(LI 参照カウントはGCによる停止時間の問題をなくすわけではなく、
単に抑えるにすぎません。)
)
$(P C++標準として提案されている shared_ptr<> は参照カウントを実装し、
以上すべての欠点を抱えています。shared_ptr<> と Mark&Sweep
を厳密に比較したベンチマークはまだ見たことがありませんが、
shared_ptr<> が速度とメモリ消費の両面で大負けしたとしても
私は驚きません。
)
$(P とは言ったものの、D でも将来のオプションとしてある種の参照カウントを
サポートする可能性があります。例えばファイルハンドルのような
個数の少ないリソースを管理するのには参照カウントは悪くない方式です。
さらに付け加えるならば、もし参照カウントでなければいけない理由があるならば、Phobos には
$(LINK2 phobos/std_typecons.html#RefCounted, std.typecons.RefCounted) 型があり、
この機能を C++ の shared_ptr<> 同様ライブラリとして実装しています。
)
$(ITEM gc_1, ガベージコレクションは遅くて予測不能なんでしょ?)
$(P その通りです。でも、malloc/free も含めて $(B どんな) 動的メモリ管理も、
遅くて、実行時間は予測不能なものです。
実際にリアルタイム系のソフトを作っている人に聞くと、
正確性が必要な場面では彼らはmalloc/freeは使わないと言います。
全てのデータをあらかじめアロケートしておくのです。
しかしながら、mallocの代わりにGCを使うことでより進んだ言語機能
(とりわけ、より強力な配列操作) が利用可能になり、
結果として必要となるメモリ割り当ての回数も減少します。
このため、明示的メモリ管理よりも GC の方が現実には高速になることを意味しています。
)
$(ITEM pure, 十分に賢いコンパイラなら、関数がpureかどうか自動的に判別できるんじゃないの?)
$(P コンパイラは pure 性(と safe 性、nothrow 性)を、function と delegate リテラルについては推論します。
通常の関数に対してこれを行わないのは幾つか理由があります:
)
$(OL
$(LI ほとんどの関数は、別の関数を呼び出し、そこからも更に他の関数が呼び出されます。
そのうちに、ソースがコンパイラにはわからないライブラリルーチンの呼び出しに行き着きます。
そのような関数は pure でないと仮定するしかありません。
pure 属性を導入することで、外部ライブラリのpureな関数は
pureとマーク付けすることが可能になり、
解析が多くのケースでうまく動作するようになります。
)
$(LI 仮想関数 (および、関数ポインタやdelegate)
でユーザーによって拡張されることを意図されたコードでは、
コンパイラからはそれらがpureかpureでないかわからず、常にpureでないと仮定しなければなりません。
)
$(LI プログラマがある関数をpureに書いたつもりで、
コンパイラがそうでないと判断した場合、これがプログラマに気づかれない可能性があります。
もっと悪いことに、プログラマが気づいたとしても、
なぜコンパイラがそう判断したのかを理解するのはいくらでも難しくなりえます
- 果たしてプログラムのミスなのかコンパイラのバグなのか?
)
)
$(ITEM minimum precision, $(D cast(float)) がその通りに動かないなら何故サポートしているの?)
$(P 浮動小数点数の規則では、 $(D cast(real)cast(float)) を
$(D cast(real)) に変換するのは妥当な変換とされます。
なぜなら、
浮動小数点数の規則は以下の原理を念頭に置いているからです:
)
$(BLOCKQUOTE_PLAIN 浮動小数点数の精度があがると動作がおかしくなるアルゴリズムは、間違っている。
浮動小数点の精度は常に最小であると考えるべきで、最大ではない。)
$(P 最大精度に合法的に依存してもよいプログラムは:)
$(OL
$(LI コンパイラ/ライブラリの検証テストプログラム)
$(LI 精度をプログラム的に判定しようとするコード片)
)
$(P ですが、(1) は通常のプログラマの気にするところではありませんし、
精度を確かめるには他の手段もあります。)
$(P (2) については D にはその目的のためのプロパティが用意されています。)
$(P 最大精度に依存するプログラムは、再考するか再設計の必要があります。)
$(ITEM nested_forward_references, ネストした関数が前方参照できないのはどうして?)
$(P 関数内の宣言は、モジュールスコープでの宣言とは異なります。
関数内では、変数の初期化が書いた順で実行されると保証されており、
ネストした関数は、その上で宣言されたすべての変数を参照できてしまうため、
これを好きに前方参照できるようにしてしまうと初期化順の保証を壊す可能性があるのです。
)
----
int first() { return second(); }
int x = first(); // x は y に依存しているが、y は未初期化
int y = x + 1;
int second() { return y; }
----
$(P しかし、(例えば相互再帰したネスト関数など)ネスト関数の前方参照が必要になることも時にはあります。
もっとも一般的な解決策は、ローカルのネスト構造体を作ることです。
構造体の関数(それと変数も!)は、順序に関する制約を持ちませんので、
相互に前方参照することができます。
)
$(COMMENT
> Single inheritance may be easier to implement, but you are losing
>something. It's a little concerning how often folks here take the
>opinion that "Feature X has problems and I never use it anyway, so no
>body else 'really' needs it." I'm not specificly blaming you, but i've
>lost track of how many time if seen that reasoning tonight. I'm afraid
>I'll see it a lot in the 275 I still have to read.
Your reasoning has merit. The counterargument (and I've discussed
this at length with my colleagues) is that C++ gives you a dozen ways
and styles to do X. Programmers tend to develop specific styles and do
things in certain ways. This leads to one programmer's use of C++ to
be radically different than another's, almost to the point where
they are different languages. C++ is a huge language, and C++
programmers tend to learn particular "islands" in the language
and not be too familiar with the rest of it.
Hence one idea behind D is to *reduce* the number of ways X can be
accomplished, and reduce the balkanization of programmer expertise.
Then, one programmer's coding style will look more like another's,
with the intended result that legacy D code will be more maintainable.
For example, over the years I've seen dozens of different ways that
debug code was inserted into a program, all very different. D has one
way - with the debug attribute/statement. C++ has a dozen string
classes plus the native C way of doing strings. D has one way of
doing strings.
I intend to further help this along by writing a D style guide,
"The D Way". There's a start on it all ready with the document
on how to do error handling:
www.digitalmars.com/d/errors.html
)
)
Macros:
TITLE=よくある質問
WIKI=FAQ
CATEGORY_FAQ=$0
ITEMR=$(LI $(LINK2 #$1, $+))
ITEM=<hr><h3><a name="$1">$+</a></h3>