forked from kinaba/dlang-ref-jp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoverview.dd
More file actions
1124 lines (884 loc) · 43.9 KB
/
overview.dd
File metadata and controls
1124 lines (884 loc) · 43.9 KB
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
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Ddoc
$(D_S 概要,
$(SECTION2 D って何?,
$(P Dは、汎用のシステム/アプリケーション
プログラミング言語です。
高級言語ですが、高速なコードを書く能力や、
OS の
<acronym title="Application Programming Interface">API</acronym>
やハードウェアへの直接アクセスの機能も維持しています。Dは、
中規模から100万行単位の大規模ソフトウェアをチームで開発するのに適しています。
Dは学習が簡単で、
プログラマを補助する沢山の機能を提供し、
コンパイラの強力な最適化技術と相性の良い言語です。
<img src="images/d3.gif" border=0 align=right alt="D Man">
)
$(P Dはスクリプト言語でも、
インタプリタ言語でもありません。
<acronym title="Virtual Machine">VM</acronym> を持たず、
宗教やおおげさな哲学とも縁がありません。
信頼性・保守性の高い・読みやすいコードを書いて仕事をサクサク進める必要のある
現実的なプログラマのための、
現実的な言語です。
)
$(P D は、様々な言語のコンパイラを実装し、
その言語で大きなプロジェクトを構築してきた数十年の経験の集大成です。
D はそれらの言語(特に、C++)からインスピレーションを受け、
経験によって、
現実の実用性の面から調整して取り込んでいます。
)
)
$(SECTION2 なぜ、 D ?,
$(P なぜ、まったく、誰がまた新しいプログラミング言語を必要とすると言うのでしょうか?
)
$(P ソフトウェア産業は、C言語が開発されて以来、
長い道を歩んできました。
沢山の新しい概念が C++言語 に盛り込まれましたが、C との互換性、
特にCの設計上の欠点もほとんど全て、そのまま保たれています。
それらの欠点を修正しようという試みは多くありましたが、
しかし、互換性の問題が足かせになっていました。
一方で、CもC++も、新機能の増大を経験しています。
これら新機能は、
古いコードを書き直す必要がないように、
既存の機構に注意深くはめ込まれなければなりませんでした。
その結果は、物凄い複雑さ - C言語の標準規格は約500ページ、
C++ に至っては 750ページ! - です。
C++ は実装するのにコストがかかり難しい言語で、
その結果、異なる実装の間で完全に移植性のある C++
コードを書くのはかなりイライラする作業となってしまいました。
)
$(P C++では、可変長配列や文字列の結合といった機能は言語の一部ではなく、
標準ライブラリとして実装されています。
$(REDO 言語のコアの一部でないということは、
幾つか $(LINK2 cppstrings.html, 最適でない結果) をもたらします。))
$(P C++のパワーと可能性を取り出して再設計し、
単純で、
直交性のある、
実用的な言語へと変換することは可能でしょうか?
その言語を、
コンパイラ作成者が正しい実装を簡単に書けるように、
そして積極的に最適化を進めたコードを生成できるように、
まとめあげることは果たしてできるのでしょうか?
)
$(P 現在のコンパイラ技術は進歩の結果、
かつて未熟だったコンパイラ技術を補うために存在した
幾つかの言語仕様を省くことができるようになりました。
(例としては、C言語のキーワード $(SINGLEQUOTE register)
であったり、
もっと微妙な例ではCのマクロプリプロセッサがあります。)
私たちは現在のコンパイラ最適化技術に頼って、
原始的なコンパイラからまともな品質のコードを得るために必要だった言語仕様から
抜け出すことができます。
)
$(SECTION3 D言語の設計の主な目標,
$(P 言語設計の全ては、何らかのトレードオフです。
なにかの原理を常に念頭に置いておくことは、正しい決定をする助けになります。)
$(OL
$(LI コンパイラからコンパイラへ、
マシンからマシンへ、
OSからOSへの移植できるコードを簡単に書けること。
実用的でありうる範囲で可能な限り、未定義動作や処理系依存の動作を取り除くこと。)
$(LI よくある間違いを無くす、あるいは少なくとも減らすように構文と意味論を構成すること。
サードパーティの静的コード検査器の必要を減らす、
あるいは完全に無くすこと。)
$(LI メモリ安全なプログラミングのサポート。)
$(LI マルチパラダイムプログラミングのサポート。つまり少なくとも、
手続き型、構造化、オブジェクト指向、ジェネリックプログラミング、
さらに関数型プログラミングをサポートすること。)
$(LI 間違ったやり方より正しいやり方の方が簡単に書けるようにすること。)
$(LI CやC++, Javaに慣れたプログラマに対する
短い学習曲線。)
$(LI 低レベルなマシン直接操作を自由にできる言語の提供。
腕利きのプログラマならば、必要な時には言語のチェックを迂回できる方法を提供すること。)
$(LI コンパイラの実装が十分に簡単な言語にすること。)
$(LI 各環境でのCアプリとのバイナリインターフェイス互換性の保持。)
$(LI DのコードがCと同じに見えるときには、同じに振る舞うか、
明示的にエラーを出すかのどちらかにすること。)
$(LI 文脈自由な文法。
意味解析なしで構文解析ができるようにすること。)
$(LI 国際化されたアプリケーションを容易に書けるようサポート。)
$(LI 契約プログラミングや単体テストとの相互運用性。)
$(LI 軽量の、単独で動作するプログラムをビルド可能。)
$(LI ドキュメント作成の手間を削減。)
$(LI コンパイラの最適化技術の進展を有効活用できるような十分な意味論の提供。
)
$(LI 数値解析プログラマの必要に応えること。)
$(LI 当然ながら、これら複数のゴールはしばしば衝突します。
その解消は、usability の良い案を優先する、という方針で行われます。)
)
)
$(SECTION3 既存言語から引き継いだ特徴,
$(P D の見かけは、全体的に C や C++ に似ています。これによって、
Dを学習したりコードを移植したりするのが容易になります。
C/C++ から D への以降は自然で、
新しいことを丸々学んだりする必要がありません。
)
$(P Dを使うと言うことは、
プログラマが特別な実行時VM (仮想マシン) に縛られる
Java VM や Smalltalk VM のような機構とは無関係です。
D VM なんてものは存在せず、
D は普通にリンクできるオブジェクトファイルを生成する、
直接的なコンパイラです。D は C と同様にOSに直結しています。
$(B make) のような一般的なツールも、
Dの開発にピッタリ使うことができます。
)
$(UL
$(LI 全体的なC/C++の $(B ルック&フィール) は維持されています。
同じように数式を書けますし、ほとんどの式や文、
全体的なレイアウトも同じ形です。
)
$(LI D のプログラムは、
C の $(B 関数とデータ) スタイルでも
C++ の $(B オブジェクト指向) スタイルでも
C++ の $(B テンプレートメタプログラミング) スタイルでも
あるいはその3つの混合でも記述できます。
)
$(LI $(B コンパイル/リンク/デバッグ) という開発モデルも引き継いでいます。
Dをバイトコードへコンパイルしたり
インタープリタで動かしたりすることを妨げる要因もまた、
ありませんが。
)
$(LI $(B 例外処理)。
例外処理に関する経験を積めば積むほど、エラーコードやグローバル変数
errnoを使うCの伝統的な方法と比べて、
例外による方法が優れていることがわかります。
)
$(LI $(B 実行時型識別)。
これはC++に部分的に実装されています。D では、
これをさらにもう一歩進めました。実行時型識別に完全に対応することで、
よりよりガベージコレクションやデバッグのサポート、
より自動化された永続性などが可能になります。
)
$(LI $(B Cの呼び出し規約) を持つ関数との呼び出し互換性を維持しています。
Dのプログラムから直接OSのAPIへアクセスできます。
プログラマの、
既存のプログラミングAPIやパラダイムに関する知識と経験は、
最小の作業でDへと引き継ぐことができます。
)
$(LI $(B 演算子オーバーロード)。
D のプログラムは、演算子オーバーロードを有効にすることで、
ユーザー定義型によって基本型を拡張できます。
)
$(LI $(B テンプレート メタプログラミング)。
テンプレートは generic programming を実装する方法の一つです。
他には、マクロを使うとか可変データ型(Variant)を使うといった方法があります。
マクロを使うのは駄目です。Variantを使うのは直接的ですが、
非効率ですし型チェックの欠如が問題です。
C++のtemplateが難しいのは、その複雑さが原因でした。
言語の構文とうまくなじまず、
その上に変換やオーバーロードの大量の規則が築かれているなどなど。。。
D では、template を使うずっと簡単な方法を提供します。
)
$(LI <acronym title="Resource Acquisition Is Initialization">$(B RAII)</acronym>
(「リソース獲得は初期化時に」イディオム)。
RAII のテクニックは、
信頼性の高いソフトウェアを書くために欠かすことのできない部分です。
)
$(LI $(B Down and dirty programming)。 D には、
低レベルでダーティなプログラミングをする能力が保たれています。
他の言語でコンパイルした外部モジュールなどに頼る必要はありません。
システム関係の仕事をしていると、時には、
ポインタを使う必要やアセンブラを弄る必要が出てくるものです。
D の目標は、低レベルでダーティなプログラミングを $(I 妨げる) ことではなく、
日常的なコーディングの際にその必要を最小にすることです。
)
)
)
$(SECTION3 取り除かれた特徴,
$(UL
$(LI Cとのソースコード互換性。互換性を保ったCの拡張は、
既になされています(C++ と ObjectiveC)。
この方面でのこれ以上の拡張は、
大量のレガシーなコードが足かせになりますし、
大した改善も見込めないように思います。
)
$(LI C++とのリンク互換性。C++の実行時オブジェクトモデルは複雑すぎます
- これ適切にサポートするとなると、D を完全な C++
コンパイラにするのと本質的に変わりません。
)
$(LI Cのプリプロセッサ。マクロプリプロセスは、言語を拡張して、
実際にはない(デバッガには見えない)模造の特徴を追加する簡易な方法です。
条件コンパイルや、テキストの #include 、
マクロ、トークン結合など…
実質的にCは明確な区別のない二つの言語の混在となっています。
さらに悪いことに(もしかしたら幸いなことに?)C
のプリプロセッサは非常に原始的なマクロ言語です。
今が、一度振り返ってプリプロセッサの用途を見直し、
それらの用途をカバーする設計を言語自体に組み込む時です。
)
$(LI 多重継承。データテーブルの値に関する複雑な機能です。
効率良くこれを実装するのは非常に大変で、
実装の際にコンパイラに沢山のバグを持たらす傾向にあります。
<acronym title="multiple inheritance">MI</acronym>
のほとんど全ての価値は、
単一継承にインターフェイスとアグリゲートを合わせれば達成できます。
残った部分だけでは、
MIを実装する手間を正当化するには足りません。
)
$(LI 名前空間。
独立に開発されたコードどうしで名前が衝突することを避けることを
目的とした技術です。モジュールを使う考え方の方が簡単で、
ずっとうまく動作します。
)
$(LI タグ名空間。構造体のタグ名を別のシンボルテーブルに置く、というのは
C言語の間違った機能です。C++
ではタグ名と通常のシンボル名を一つに合わせると同時に、
古いCコードとの後方互換性をも残そうとしました。
結果は、不必要な混乱を招くものになっています。
)
$(LI 前方宣言。Cコンパイラは、
カレント状態よりテキスト的に前に処理した部分のみを知っています。
C++はこれを少しだけ拡張して、
クラスのメンバ同士は順番によらず参照可能になりました。Dはこれを
その当然の論理的帰結へと押し進め、前方宣言は完全に不要になりました。Cでは、
前方宣言を書くのを嫌って呼び出し関係の順に関数を並べることがよくありましたが、
Dではモジュールレベルで、
自然な順序に関数を書くことができます。
)
$(LI ファイルのinclude。
コンパイル単位毎に巨大なファイルを何度もparseするのは、
コンパイルを遅くさせる主な原因となっています。ファイルの取り込みは、
シンボル表の import によってなされるべきです。
)
$(LI 三連文字や二連文字。今は Unicode の時代です。
)
$(LI 非仮想メンバ関数。C++では、関数がvirtualになるかどうかは
クラスの設計者が前もって決定します。
メンバ関数をオーバーライドすることにしたのに、基底クラスの方で改造を忘れる…
というのは、よくある(けれども非常に見つけにくい)コーディングミスです。
全てのメンバはvirtualにしておき、
オーバーライドが存在しないことをコンパイラが検知して非
virtual に変える、というアプローチの方が信頼性があります。
)
$(LI 任意サイズのビットフィールド。ビットフィールドは複雑で、
非効率かつめったに使われない機能です。
)
$(LI 16bitマシンのサポート。
Dでは、near/far ポインタをはじめとする、良い
16bit コードの生成に必要な機能は考慮されていません。
D言語は、最低32bitのフラットなメモリ空間を前提に設計されています。
Dは64bitアーキテクチャにはうまくフィットします。
)
$(LI コンパイラパスの相互依存。C++では、ソーステキストをきちんと構文解析するには
シンボル表と、様々なプリプロセッサ命令が必要です。このせいで、
C++のソースをあらかじめparseしておくことが不可能になり、また、
コード解析ソフトや構文強調を行うエディタを正確に実装するのが
無茶苦茶大変になっています。
)
$(LI コンパイラの複雑さ。
実装の複雑さを軽減することで、
複数の $(I 正しい) 実装が登場しやすくなります。
)
$(LI 低機能な浮動小数点数。
今やモダンな浮動小数点演算器の乗ったハードウェアが使われている以上、
マシン間の最小公約数にあわせた低機能なものではなく、
高度な浮動小数点数の機能がプログラマに使えるようになっているべきです。
特に、Dの実装は必ず IEEE 754 算術をサポートすることになっており、
また拡張精度演算のあるハードウェアではそれも必ずサポートされることになっています。)
$(LI テンプレートでの、< と > の多重利用。
この記号が選択されたことで、プログラマとC++実装者とC++ソース解析ツールのベンダの間には、
長年の間、バグと嘆きと困惑が積もり積もっています。
これがあるせいで、ほとんど完全なC++コンパイラそのものを作らない限り、
正しくC++のコードを構文解析するのは不可能になっています。
D は !( と ) を使っており、
見た目も悪くありませんし文法も明確になっています。
)
)
)
$(SECTION3 D を必要とする人は?,
$(UL
$(LI 日常的にlintなどのコード分析ツールを使って、
コンパイルより前にバグを取り除こうとしているプログラマ。
)
$(LI コンパイラの警告レベルはいつも最大にして、
警告はエラーとして扱うように設定している人。
)
$(LI Cでよくあるタイプのバグを避けられるようなプログラミングスタイルを採用したい、
と考えているプロジェクト管理者。
)
$(LI C++は複雑すぎてオブジェクト指向プログラミングを十分に行えない、
と考えている人。
)
$(LI C++の強力な表現力は好きだけれど、
明示的なメモリ管理や
ポインタ周りのバグには
悩まされているというプログラマ。
)
$(LI built-inのテストや検証機能が必要なプロジェクト。
)
$(LI 何百万行にもなるアプリケーションを書くチーム。
)
$(LI 言語は、
直接ポインタを扱うことによる危険性を未然に不要にするだけの
十分な機能を提供すべきだ、と考えているプログラマ。
)
$(LI 数値計算プログラマ。
D は、数値計算に必要な機能を多く直接サポートしています。
例えば、拡張精度浮動小数点数や
組み込みの複素数と虚数型、
<acronym title="Not A Number">NaN</acronym>
や∞に対する動作の定義など。
(これらは新しいC99標準には追加されましたが、
C++には存在しません。)]
)
$(LI アプリケーションを基本的にはRubyやPythonのようなスクリプト言語で書いて、
ボトルネック部分だけスピードを稼ぐためにC++で書いているようなプログラマ。
Dには、
RubyやPythonにあるような生産性の高い機能が多く実装されていて、
アプリケーション全体を1つの言語で書くことが可能になっています。)
$(LI Dの字句解析器と構文解析器は、お互いに、そして意味解析器とも完全に独立しています。これは、
コンパイラを全て作りあげずとも、Dのソースを扱うツールを簡単に書けることを意味しています。
これはまた、特別なアプリケーションのために、
ソースをトークン分けした状態で伝達できることも意味しています。
)
)
)
$(SECTION3 D を必要としない人は?,
$(UL
$(LI 現実問題として、
何百万行ものCやC++プログラムをDへ変換する人はいないでしょう。
DはC/C++のコードをそのままではコンパイルできないため、
過去のレガシーなソフトの開発にはDは使えません。
(しかしながら、
D はレガシーな C の API はしっかりサポートしています。
D からは、C言語インターフェイスを提供しているコードであれば全て直接呼び出すことができます。)
)
$(LI 最初に学ぶプログラミング言語として。
Basic か Java が初心者には向いています。
D は、中級~上級者プログラマが二番目に修得する言語として優れています。
)
$(LI 言語原理主義者。 D は実用的な言語であって、
どの側面もその観点から作られています。理想を追う観点からではありません。
例えば、D ではポインタの必要性を実質的になくすセマンティクスが組まれています。
しかし、時には規則を破る必要もありますから、
ポインタはまだ残されています。
同様に型システムを上書きする必要のあるときを考え、
キャストもまた残っています。
)
)
)
)
$(SECTION2 D の主要な特徴,
$(P この節では、様々なカテゴリにわたる、
D の興味深い特徴をリストアップします。
)
$(SECTION3 オブジェクト指向プログラミング,
$(SECTION4 クラス,
$(P D のオブジェクト指向的特徴は、
クラスによるものです。
継承のモデルは、
単一継承 + インターフェイス となっています。
Objectクラスが継承階層のルートに存在し、
全てのクラスがその機能を実装します。
クラスは参照としてインスタンス化されるため、
例外発生時の複雑なクリーンアップコードが必要でなくなります。
)
)
$(SECTION4 演算子オーバーロード,
$(P クラスは、新しい型をサポートするよう型システムを拡張することで、
既存の演算子と共にはたらくように作ることができます。
例としては、bignumber クラスを作って、通常の代数的な構文を使えるよう、
+, -, *, / 演算子をオーバーロードする、などがあります。
)
)
)
$(SECTION3 関数型プログラミング,
$(P 関数型プログラミングは、カプセル化や並行プログラミング、メモリ安全性、
プログラム合成などに多くの利点をもたらします。
Dでの関数型のプログラミングスタイルをサポートする機能は、以下の通りです:
)
$(UL
$(LI pure 関数)
$(LI immutable 型とデータ構造)
$(LI 無名関数とクロージャ)
)
)
$(SECTION3 生産性,
$(SECTION4モジュール,
$(P ソースファイルは、モジュールと1対1に対応しています。
ファイルから宣言をテキストとして #include する代わりに、
単にモジュール内のシンボルを import します。
複数回同じモジュールをimportする心配は不要で、
ヘッダを $(D #ifndef/#endif) で囲うラッパや $(D #pragma once)
などの必要がなくなりました。
)
)
$(SECTION4 宣言 vs 定義,
$(P C++という言語は通常、関数やクラスを2回宣言することを要求します -
.h ヘッダファイルに書く宣言と、.c ソースファイルに書く定義と。
これはエラーを生みやすく、退屈な作業です。明らかに、
プログラマが記述する必要があるのは1回だけで、
あとはコンパイラがシンボルのimportに必要な宣言情報を取り出せばよいのです。
そしてそれが、まさしくDのする動作です。
)
$(P 例:
)
-----------------------
class ABC
{
int func() { return 7; }
static int z = 7;
}
int q;
-----------------------
$(P もはや、メンバ関数やstaticメンバ、externなどの定義を分けて書く必要はありません。
次のようなわずらわしい構文も不要です:
)
$(CCODE
int ABC::func() { return 7; }
int ABC::z = 7;
extern int q;
)
$(P 注:もちろん、C++ でも $(D { return 7; }) のような単純な関数は
インライン で書けます。が、複雑なものはそうではありません。それに加え、
前方参照がある場合は関数のプロトタイプ宣言が必要になります。
次のコードはC++では動作しません:
)
$(CCODE
class Foo
{
int foo(Bar *c) { return c->bar(); }
};
class Bar
{
public:
int bar() { return 3; }
};
)
$(P しかし、これと同等のDのコードは動作します:
)
-----------------------
class Foo
{
int foo(Bar c) { return c.bar; }
}
class Bar
{
int bar() { return 3; }
}
-----------------------
$(P Dの関数がインライン化されるかどうかは、
最適化の設定によって決定されます。
)
)
$(SECTION4 テンプレート,
$(P D のテンプレートは、部分特殊化能力の提供によって、
ジェネリックプログラミングを綺麗にサポートします。
テンプレートクラスもテンプレート関数も利用可能で、
可変個引数テンプレートやタプルといった強力な機能を備えています。
)
)
$(SECTION4 連想配列,
$(P 連想配列は、自然数のindexに制限されず、
任意の型の値を配列の添え字として使えるようにした配列です。
連想配列の本質は、ハッシュ表です。連想配列によって、
高速で効率的な、
バグのないシンボルテーブルが簡単に実装できます。
)
)
$(V1
$(SECTION4 Real Typedef,
$(P C と C++ の typedef は、本当は型の $(I 別名) に過ぎず、
新しい型は実際には導入されていませんでした。D は、本物のtypedefを実装しています:
)
-----------------------
typedef int handle;
-----------------------
$(P このコードは、実際に新しい型 $(B handle) を作成します。
型チェックが働き、typedefされた型で関数をオーバーロードできます。
例えば:
)
-----------------------
int foo(int i);
int foo(handle h);
-----------------------
)
)
$(SECTION4 ドキュメント化,
$(P ドキュメント化は、従来、2つのステップに分かれて行われてきました
- まずコメントとして機能の説明が書かれ、
それとは別のhtmlやmanページとして改めて書き直されるという形で。
当然の帰結として、時間がたつにつれ、コードは更新されても分離されたドキュメントは
更新されず、次第に説明と実態が乖離していくようになります。
ソースに書き込まれたコメントから
必要なドキュメントを直接生成できるようにすることで、
ドキュメント書きの時間を半分に減らせるだけでなく、
コードとドキュメントの一貫性を保つのもずっと簡単になります。
$(LINK2 ddoc.html, Ddoc) が、Dのドキュメント生成の仕様となっています。
このページもDdocによって生成されています。
)
$(P C++にもサードパーティ製のツールはいくつか作られましたが、
それらには重大な欠点がありました:
$(UL
$(LI C++を100%完全に構文解析するのは非常に難しい作業で、実質的に、
完全なC++コンパイラを書くのと同等な作業が必要です。サードパーティ製のツールは大抵、
C++の一部分だけしか正しく解析できず、
書けるコードがそれによって制限されてしまいます。)
$(LI 異なるコンパイラは異なったバージョンのC++をサポートし、
異なる拡張をC++に施しています。
サードパーティ製のツールでは、これら全てをカバーするのは困難です。)
$(LI サードパーティ製のツールは、
必要な全てのプラットフォームで動作しないことがあります。
コンパイラとは別々の更新サイクルが必要になります。)
$(LI ドキュメント化ツールをコンパイラの一部として組み込むことで、
全てのDの実装で標準化されます。いつでもデフォルトのものが使えるということは、
コメントによるドキュメント生成がより一層使われうることを意味しています。)
)
)
)
)
$(SECTION3 関数,
$(P D には、グローバル関数、関数のオーバーロード、インライン化、
メンバ関数、仮想関数、関数ポインタ…など、
従来通りの関数は期待されるとおりにサポートしています。
それに加えて:
)
$(SECTION4 ネストした関数,
$(P 関数は他の関数の中にネストすることができます。
これは、コードの局所性や、
関数クロージャを使うテクニックで有用です。
)
)
$(SECTION4 関数リテラル,
$(P 無名関数を式中に直接埋め込めます。
)
)
$(SECTION4 動的クロージャ,
$(P ネストした関数やクラスのメンバ関数は、
クロージャ(デリゲートとも呼ばれます)
として参照でき、ジェネリックプログラミングをより簡単で型安全にします。
)
)
$(SECTION4 in$(COMMA) out$(COMMA) ref 引数,
$(P これらの引数を指定するのは、
関数の可読性を上げるだけでなく、
何も失うことなくポインタの必要な場面を減らし、また、
コンパイラがコードの問題を発見しやすくする可能性を残します。
)
$(P これによって、D を様々な外部のAPIと直接繋ぐことが可能になります。
"インターフェイス定義言語 (IDL)"
のような対策は不要になるでしょう。
)
)
)
$(SECTION3 配列,
$(P Cの配列には、いくつか直すべき欠点があります:
)
$(UL
$(LI 配列に次元情報が保持されず、
別に格納したり引数として渡す必要があります。
皆さんご存じの例をあげれば、
$(D main(int $(D_PARAM argc), char *$(D_PARAM argv)[])) の引数です。
(Dでは、main は $(D main(char[][] $(D_PARAM args)))と宣言されます。)
)
$(LI 配列がfirst-classオブジェクトではありません。配列を関数へ渡すと、
例えプロトタイプ宣言は配列に見える書き方をされていても、
ポインタに変換されます。
この変換によって、全ての配列型情報は失われます。
)
$(LI Cの配列はサイズを変更できません。これは、単純な構造、例えばスタックでさえ、
複雑なクラスとして構成しなければならないことを意味しています。)
$(LI Cの配列はどこが境界であるかの情報を持たないため、
境界チェックができません。)
$(LI 配列は識別子の後ろに []
を置くことで宣言されます。
これは、配列へのポインタなどを宣言する際に構文がややこしくなる原因です:
$(CCODE
int (*array)[3];
)
$(P Dでは、配列宣言の [] は左に行きました:
)
-----------------------
int[3]* array; // int の3要素配列 へのポインタ を宣言
long[] func(int x); // longの配列を返す関数の宣言
-----------------------
$(P ずっと理解しやすくなっています。
)
)
)
$(P Dの配列には、
ポインタ、静的配列、動的配列、連想配列といった種類があります。
)
$(P 参照: $(LINK2 arrays.html, 配列).
)
$(SECTION4 文字列,
$(P 文字列の処理は非常にありふれた作業ですが、C/C++では扱いにくいものになっています。
この機能は、言語の直接サポートが必要です。
モダンな言語は文字列の連結やコピーなどをサポートしますが、D も同様です。
文字列周りの改善は、配列の扱いを改善したことの直接の帰結です。
)
)
)
$(SECTION3 リソース管理,
$(SECTION4 自動メモリ管理,
$(P Dのメモリ割り当ては完全にガベージコレクタの下で行われます。
C++では経験的に、メモリ解放を管理するためには複雑な機能が
沢山必要であることがわかっています。ガベージコレクタによって、
言語は非常に簡単になります。
)
$(P 今は、ガベージコレクションは怠け者や初心者プログラマのためのものだ、
という認識があります。これと同じことが C++
に対しても言われていたのを思い出します。C++にできてCでできないこと、
もっと言えばアセンブラでできないこと、は結局の所存在しないのだそうな。
)
$(P ガベージコレクションは、
CやC++では必要だった、
面倒な、
エラーの元になるメモリ割り当て管理のコードを不要にします。
これは開発時間を早め保守のコストを下げるだけでなく、
できたプログラムもしばしばより高速に動作するようになるのです!
)
$(P もちろん、C++で使えるガベージコレクタはありますし、
実際私も自分の
C++のプロジェクトでは使っています。しかしながら、
この言語はGCとの親和性が悪く、その効果性は十分発揮されません。
ランタイムライブラリの大くもGCと同時に使うことができないのです。
)
$(P より完全な議論については、
$(LINK2 garbage.html, ガベージコレクション) の項をご覧下さい。
)
)
$(SECTION4 明示的なメモリ管理,
$(P DはGCを採用した言語ではありますが、
特定のクラスでは new/delete
演算をオーバーライドして、独自のメモリ割り当てを行うことができます。
)
)
$(SECTION4 RAII,
$(P RAII は、リソースの管理と解放を管理するための、
モダンなソフトウェア開発技術です。
Dは、RAIIをガベージコレクションのサイクルとは独立の、
制御・予測可能な方法でサポートします。
)
)
)
$(SECTION3 パフォーマンス,
$(SECTION4 Lightweightな構造体,
$(P D は、C形式の単純な構造体をサポートしています。これには、
Cのデータ構造との互換性と、クラスの能力が過剰であるときに使えるように、
との二つの理由があります。
)
)
$(SECTION4 インラインアセンブラ,
$(P デバイスドライバやハイパフォーマンスが必要なシステムアプリケーション、
組み込みシステムなど、特化されたコードはしばしば、
アセンブリ言語に浸って仕事をなしとげる必要があります。
Dの実装は必ずしもインラインアセンブラを実装する必要はありませんが、
インラインアセンブラは、言語の一部として定義されています。
ほとんど場合必要なアセンブラコードは扱えるので、別のアセンブラやDLLは不必要になります。
)
$(P 多くのDの実装は、Cでのそれに似た、
組み込み関数をサポートしています。
I/Oポートの制御や特別な浮動小数点数演算への直接アクセスなどができます。
)
)
)
$(SECTION3 信頼性,
$(P モダンな言語は、できる限り、プログラマがバグを発見する手助けとなるべきです。
様々な形の"手助け"があります。
よりロバストな技術を簡単に使えるようにしたり、
明らかに間違ったコードを実行時に検出させるフラグをコンパイラにつけるなどなど。
)
$(SECTION4 契約,
$(P 契約プログラミング
(Contract Programming。B. Meyer によって発明されました)は、
プログラムの正しさを保証する助けとなる革命的な技術です。
DでのDBCは、関数の事前条件、事後条件、クラス不変条件、
assert契約を含んでいます。
Dの実装については、$(LINK2 dbc.html, 契約) の項をご覧下さい。
)
)
$(SECTION4 単体テスト,
$(P 単体テストをクラスへ追加して、プログラムの起動時に自動実行することができます。
この機能は、気付かぬ内にクラスの実装にバグが入っていないかを、
ビルドのたびに確かめる助けになります。
単体テストは、クラスのソースコードの一部です。
書き上げたコードをテスターに放り投げる従来のテスト方法とは対照的に、
テストを作ることが、自然にクラスの開発の過程に含まれるようになります。
)
$(P 単体テストは他の言語でも可能ですが、
言語自体がその概念にぴったり適合していないため、
しっくりこない結果になります。単体テストは D の最大の特徴です。
Dのライブラリ関数は、単体テストによって、実際に関数が動くことの保証と、
使い方の説明の両方がうまくなされています。
)
$(P WebでダウンロードできるC++のライブラリや、
アプリケーションのコードを考えて下さい。
そのうちのどれだけが、単体テストはもちろん、*多少なりとも*検証を行っているでしょう。
1% 未満? 普通我々は、コンパイルが通ったなら、動作すると仮定しています。
そして、コンパイラが警告を吐くと、実際にバグなのかそれとも余計なお世話なのか、
疑問に思って悩む程度です。
)
$(P 単体テストを契約プログラミングとともに用いることで、D は、
信頼性のあるロバストなシステムを構築するための最高の言語となります。
単体テストは、手に入れたDのコード片の質の簡単な評価手段にもなります
- つまり、もしそのコードに単体テストや契約が書かれていなければ、
却下。
)
)
$(SECTION4 debug属性・debug文,
$(P デバッグは、言語の構文の一部になりました。
デバッグコードは、マクロやプリプロセッサのコマンドを使わずとも、
コンパイル時に有効にしたり無効にしたりできます。
debug構文は、
リリース用とデバッグ用の両方のコードを生成しなければならない現実のソースコードを、
理解しやすく、一貫性と移植性のあるものにします。
)
)
$(SECTION4 例外処理,
$(P 単なる try-catch ではなく、より優れた $(I try-catch-finally) モデルが使われています。
$(I finally)
を実現するためのダミーオブジェクトとデストラクタを作る必要はありません。
)
)
$(SECTION4 同期,
$(P マルチスレッドのプログラミングが、どんどん主流になってきています。
そこで、D はマルチスレッドのプログラムを作るための要素を提供します。
同期処理は、メソッドまたはオブジェクト単位でなされます。
)
-----------------------
synchronized int func() { ... }
-----------------------
$(P 同期された関数は、
一度に一つのスレッドだけが実行することができます。
)
$(P 同期された文は、周りにmutexを置くことで、
オブジェクト単位、またはグローバルにアクセスを制御します。
)
)
$(SECTION4 ロバストな技術のサポート,
$(UL
$(LI ポインタの代わりに、動的配列)
$(LI ポインタの代わりに、参照変数)
$(LI ポインタの代わりに、参照オブジェクト)
$(LI 明示的メモリ管理の代わりに、ガベージコレクション)
$(LI スレッド同期処理のための組み込みプリミティブ)
$(LI コードを気付かぬうちに汚す"マクロ"を持たない)
$(LI マクロの代わりに、インライン関数)
$(LI ポインタの必要性を大幅に削減)
$(LI 整数型のサイズが明確)
$(LI char型の符号の扱いに不明確さなし)
$(LI ソースとヘッダで同じ宣言を書く必要なし)
$(LI デバッグコードの追加の明示的な構文サポート)
)
)
$(SECTION4 コンパイル時チェック,
$(UL
$(LI 強い型チェック)
$(LI ループ本体の 空の ; 禁止)
$(LI 代入の結果を論理値として使えない)
$(LI 廃止されたAPI の非推奨性チェック)
)
)
$(SECTION4 実行時チェック,
$(UL
$(LI assert() 式)
$(LI 配列の境界チェック)
$(LI switchの、未定義状態例外)
$(LI メモリ不足例外)
$(LI 事前,事後,クラス不変条件 による「契約プログラミング」サポート)
)
)
)
$(SECTION3 互換性,