これはなにか
- 2017年は新しい言語をゼロから勉強してなかったことを思い出したので、D言語をDlang-Tourで少しだけ勉強してみたのでその記録です。
- 自分用のメモを雑多にまとめたので読みづらいです。ごめんなさい。
Dlang-tourを一通り読んで手元で動かしてみた所感
- 自分はc++よりもjavaの方が経験が長いのだが
とてもjavaっぽいc
という印象を受けた。特にclassの定義はjavaと殆ど同じ。 - 最近の言語っぽく、oopも関数型スタイルもこなすマルチパラダイムな言語でありながらメモリ管理をマニュアルで出来たりと守備範囲がめっちゃ広い
- 一方で、守備範囲広すぎて、どういう用途が向いているのかパッと分からないという気もした。dlangじゃないとこれができない!というのが、自分の勉強不足が理由でまだ分かってないせいかもしれないけど…
- とはいえ、速度を求める場合やメモリ制限が厳しい場合に、バイナリをシュッと出力できるモダンでシンプルな言語がほしい時にはいいかもしれない。組み込みとか、あとは競プロにも良さそう。
なぜD言語なのか
- いつも利用してる図書館でたまたま見つけたプログラミング言語Dを勉強の息抜きで読んでみたら、思ったよりとっつきやすかったので勉強してみようと思った
学習記録
officialサイトのトップページに書いてある宣伝文句を読んで雑に訳した
- 概要
- D言語は多目的プログラミング言語だよ
- 静的型付け、システムレベルアクセス、Cっぽいシンタックス
- 安全性とプログラマーの生産性によって、効率性とコントロールとモデリングを併せ持つよ
- なんでDなの
- 利便性
- Dは動的言語のように冗長な型を書かずにでかいコードが書けるよ
- 一方で、静的インターフェースが型やプロパティを推論するので、静的世界と動的世界の良いとこどりが出来るよ
- 自動メモリ管理によって安全でシンプルで堅牢なコードにするよ
- Dはscoped resource managementとscope statementをサポートし、書きやすくて読みやすい決定論的トランザクションコードが書けるよ 1
- 線形および連想配列、slice、rangeがあるので、日々のプログラミングタスク(小さなものから大きなものまで)をシンプルかつ楽しいものにするよ
- パワー
- Dはクラシックなポリモーフィズム、値セマンティクス、関数スタイル、ジェネリクス、汎用プログラミング、契約プログラミング等を提供し、それらは全て調和を保ちつつ統合されているよ
- Dは並行性に対する革新的なアプローチを提供するよ。そのための機能として、真のイミュータブルなデータ、メッセージパッシング、デフォルトでの非共有性、複数スレッド間の真の不変データ共有管理を特徴としているよ。
- シンプルなスクリプトから大規模なプロジェクトにいたるまで、Dは、ユニットテスト、情報隠蔽、洗練されたモジュール性、高速コンパイル、正確なインタフェースなど、アプリケーションのニーズに応じて幅広く拡張できるよ
- 効率性
- Dのコードは自然と効率性の高いネイティブコードにコンパイルされるよ
- Dは大抵の「明確」なコードが速く、そして安全になるようにデザインされているよ
- 時には、速度と制御のために、型安全の境界から逃げる必要があるかもしれないけど、そのようなレアケースに備えて、Dはポインタ、型変換、C関数アクセス、手動メモリ管理、独自のアロケーター、インラインアセンブリコードを提供するよ
- 利便性
Dlang tourの最初の方を読んでみる
- まずはinstall。
- EditorはVisual Studio CodeにD Language Extensionを入れて使う。
$ brew install dmd
- package managerである
dub
を使ってprojectのtemplateが作れるらしいのでやってみる。
$ brew install dub
$ dub init hello
dub init hello
Package recipe format (sdl/json) [json]:
Name [hello]:
Description [A minimal D application.]:
Author name [KazuhiroSerizawa]:
License [proprietary]:
Copyright string [Copyright © 2017, KazuhiroSerizawa]:
Add dependency (leave empty to skip) []:
Successfully created an empty project in '/Users/seri/Documents/d-work/hello'.
Package successfully created in hello
$ cd hello
$ tree .
.
├── dub.json
└── source
└── app.d
app.d
の中身は
import std.stdio;
void main()
{
writeln("Edit source/app.d to start your project.");
}
実行するにはprojectの直下で dub run
で良いようだ。 ( dub
だけでもcompileされて実行された)
$ dub run
Performing "debug" build using dmd for x86_64.
hello ~master: target for configuration "application" is up to date.
To force a rebuild of up-to-date targets, run again with --force.
Running ./hello
Edit source/app.d to start your project.
moduleについて
- dmdコンパイラに付随する標準ライブラリはPhobosという名称がついている
- Phobosのnamespaceは
std
。c++と同じか。 -
import
キーワードでモジュールを読み込んで使えるようにする
import std.stdio;
- 読み込むシンボルを選択的に限定することもできる
import std.stdio : writeln, writefln;
- import句はファイルのトップにも書けるが、関数の中にも書ける
void main(){
import std.stdio : writln;
writeln("Hello World!");
}
moduleのpathについて
- dのnamespaceはファイル階層と一致しており、例えば
import my.cat
で検索されるのはmy/cat.d
である - 何も指定しない場合、暗黙的にimportを実行するscriptのcurrent directoryを起点としてmoduleを検索する
- moduleを検索する起点となるdirectoryを指定するにはコンパイル時に
-I
オプションでdirectoryを指定する - また指定したmoduleがファイルではなくdirectoryの場合コンパイラはそのdirectory配下の
package.d
というファイルをロードしようとする- pythonの
__init__.py
みたいなもんだろうか
- pythonの
余談:Dlang tourの日本語版に package.d
を使うpath指定についての解説が入ってなかったのでPR出した
- githubにソースがあるのでこれを修正してPR出せばいいっぽい
- importで指定したmoduleの参照先がdirectoryだった場合、package.dを自動でloadする機構は2.064で入った比較的新しい機能らしく、英語版は今年の6月に追加されているが日本語版の追加が漏れてるっぽい
- 後日、日本語版のrepositoryにPRを出して無事マージされた https://github.com/dlang-tour/japanese/pull/90
基本型
- dlangの基本型は
bool
,byte
,ubyte
,char
short
,ushort
,wchar
,int
,uint
,dchar
,long
,ulong
,float
,double
,real
- 文字列は
char
がUTF-8、wchar
がUTF-16、dchar
がUTF-32に対応でそれぞれ使われるらしい - 型が異なる変数間の型変換は精度に影響しなければ許可される
- 強制的な型変換には
cast
を使う -
auto
キーワードによって型推論ができる。auto myVar = 7;
だとmyVar
の型をint
と推測する - 全てのデータ型は、初期値となる値を
.init
プロパティとして保持している。int.init
だと0
、float.init
だとnan
を返す。
Memory管理
- dlangもポインタ演算ができる
- syntaxはc, c++と大体同じだが、mallocの代わりに
new
演算子が使える - GCがあるのでnewした変数は自分でfreeしなくてもいい
int a;
int* b = &a;
auto c = &a; // aのアドレス
int *a = new int; // cで言うところの `malloc(sizeof(int))` に該当する?
- dlangは3つのセキュリティレベルがある。
@system
,@trusted
,@safe
- デフォルトは
@system
-
@safe
はメモリ破壊を防ぐためのdのサブセットであり、@safe
なコードは@safe
または@trusted
な関数のみ呼び出せるよう制限し、ポインタ演算を禁止したりする
void main() @safe
{
import std.stdio;
writeln("Edit source/app.d to start your project.");
int a = 5;
int* p = &a;
int* c = p + 5;
}
コレを実行すると以下のエラーメッセージが出る
Error: cannot take address of local a in @safe function main
Error: pointer arithmetic not allowed in @safe functions
可変性
- javaやc++でいうところの
final
に該当するimmutable
という型修飾子がある - カレントスコープでのみ有効となる
const
もある
immutable int err = 5;
err = 6;
Error: cannot modify immutable expression err
関数定義
- よくある感じ
int add(int lhs, int rhs) {
return lhs + rhs;
}
- 関数の返り値も
auto
で推論できる
auto add(int lhs, int rhs) {
return lhs + rhs;
}
配列
- 普通の静的配列、動的配列がある
- 動的配列はスライスとも呼ばれ、range指定でデータの一部の参照を取り出すことができる
int[8] arr1; // 静的配列
int[] arr2 = new int[8]; // 動的配列
int[] arr3 = [1, 2, 3, 4, 5];
auto arr4 = arr3[1 .. $]; // スライスはrange指定で要素の参照(≠値コピー)を取り出せる
writeln(arr4); //=> [2,3,4,5];
foreach
- dにはLLにはおなじみのforeachがある
foreach (int e; arr) {
writeln(e);
}
foreach (i, e; [4, 5, 6]) { // iにはindexが格納される
writeln(i, ":", e);
}
連想配列
- いわゆるHash
int[string] hash;
hash["hogetarou"] = 1;
hash["fugatarou"] = 2;
writeln(hash["hogetarou"]); // 1
クラス
- scopeの意味はjavaやc++と同じ模様
class Any {
protected string type;
// constructor
this(string type) {
this.type = type;
}
// finalは継承を禁止する
final string getType() {
return type;
}
// private
private string hoge() {
return "hoge";
}
// 継承して実装しないと使えない
// abstractな関数が一個でもあるとnewできないabstract class扱いになる模様
abstract string convertToString();
}
次はこれ読む
-
サンプルコードを読んだ感じだとクロージャを書けるよってことらしい ↩