プログラミング言語

ここの情報は相当古くなってます。気が向いたら直します。いつになるか分からないけど。

感想

  • 言語仕様はかなりよいと思う。
  • 正直言って、ライブラリ(Phobos)がダメ。へたすると C/C++ の二の舞か?
    • Phobos では、std.c.* でCライブラリをできるかぎりそのまま使う方針になってきているようだ。
    • Tango というライブラリが再設計されている。
  • 文字列は UTF-8 なのに ASCII と区別ついていない方々がライブラリ作っていて困る。 最近は改善されている模様。
  • Phobos のマニュアルが実装に追いついていない。ライブラリのソースを直接読まないと現状が分からない。
  • 日本語での入出力に難あり。その他文字コードの変換ライブラリを何とかする必要あり。
  • Windows にべったりで構わないなら C#.NET 使う方がプログラミングとしては楽なはず。
  • D 2.0 はまだ alpha で、仕様が変わりまくってる。実用で使うなら D 1.0 ?
  • 技術者がかなり少ないので、仕事でソースを納品するものに使うのはかなり難しいと思う。自分でソースを管理できるならアリ。

HelloWorld

hello.d を以下の内容で書く。UTF-8 で保存する。

import std.stdio;

int main(string[] args)
{
    writefln("Hello, World!");
    return 0;
}

コンパイルする。

C:\>dmd hello.d
c:\dmd\bin\..\..\dm\bin\link.exe hello,,,user32+kernel32/noi;

実行する。

C:\>hello
Hello, World!
  • 実行開始点(エントリポイント)は int main(string[] args)
    • 正確には以下の4通り
      int main(string[] args)
      int main()
      void main(string[] args)
      void main()
  • return 0; は必須。(0はOS依存) これがないとエラーになる。
  • 返り値は終了コードなので OS 依存。(普通は0が正常だろう。)
  • void main() でも動くが、終了コードが不定? (Windows XP では 14 が返ってきた。)
  • writefln の代わりに printf でも動くが、0終端文字列(いわゆるC言語形式の文字列)が必要。
    • writef, writefln を使おう。
  • ソースは基本的に、UTF-8 で保存すること。Shift JIS はダメ。

main の引数

args.d

import std.stdio;

int main(string[] args)
{
    for (int i = 0; i < args.length; i++)
    {
        writefln("%d:[%s]", i, args[i]);
    }
    return 0;
}

実行結果

C:\d\args\>args Hello World "Hello, World" 'Hello, World'
0:[C:\d\args\args.exe]
1:[Hello]
2:[World]
3:[Hello, World]
4:['Hello,]
5:[World']
  • args[0] は自分の実行パスとなる。
  • コマンドラインがどう分割されるかは OS のシェルに依存。
  • 配列の長さ(要素数)は length で取る。size ではない。 (以前、size はバイトサイズを返していたが、length との混同が激しかったらしく sizeof に改名された。)

printf と writef の違い

  • printf はC言語との互換性のためにある。互換性が必要でないなら使うべからず。
  • printf はC言語の printf が呼ばれる。
  • printf で %s で char[] を表示するには、char* std.string.toStringz(char[]) での変換が必要。
import std.string;
... 
         printf("%d:[%s]\n", i, toStringz(args[i]));
  • あるいはもうひとつの方法として、サイズ付き文字列出力を使う手がある。(この場合でも0終端がある場合には、そこまでしか表示されない。)
import std.string;
... 
         printf("%d:[%.*s]\n", i, args[i]);

string と char[] の違い

  • string は今や不変オブジェクト(文字単位で書き換え不可能)になった。もはやただの char[] の alias ではない。よって、ちゃんと使い分ける必要がある。(D 2.006 から)
  • char[] は文字単位で書き換え可能。

char[] と char* の違い

  • char[] は、文字列長(配列長)を持っている。一般にUTF-8である。D言語の標準文字列。
  • char* は、文字列長(配列長)を持っていない。一般にC言語の0端末文字列。形式は不明。
  • もちろん、char[] はD言語での char 型配列に過ぎないので、&x[0]とすると char* は手に入る。しかし、端末に"\0"が付いていないから、そのままC言語関連の関数に渡すと悲惨なことになる。
  • char[] から0端末文字列にするには char* std.string.toStringz(char[]) を使う。
    • 生存期間に注意。char* を渡している最中にインスタンスが捨てられてはならない!
    • 保守的GCを使っている場合、外部に関わる生存期間は保証できない。(外で char* いじっていても気がつかれずに破棄される可能性がある。)
  • C言語で使われる「単なるバイト列としての char[]」は、D言語では byte[] か ubyte[] で扱うべきもの。文字列とバイト列は区別して扱うこと。

ストリーム入出力

  • std.stream.InputStream.readLine(char[]) は、1行を読み込む。改行コードは取り除かれる。(改行は CR/LF, CR, LF どれも同じように読み取る。)
  • std.stream.OutputStream.writeLine(char[]) は、文字列を出力して、改行を行う。
  • std.stream.OutputStream.writeString(char[]) は、文字列を出力する。
  • std.stream.OutputStream.write(char[]) は文字列長も含めて出力する。バイナリ出力と見ればよいのか? (システム依存って書いてある…)
  • 改行コードの制御はどうなっている? OS依存?
    • Phobos のファイルには「テキストモード」「バイナリモード」の概念がない。
    • writeLine, writefln など、改行コードを出力するメソッドが「OS 依存で」書き込む。
      • Windows は CR/LF, Mac は CR, Unix は LF を出力。
    • readLine など改行コードを入力するメソッドは、CR/LF, CR, LF すべてを改行とみなして読み出す。
      • readLine は改行が来るまでひたすら読み続けることになる。不定な入力が想定される場所では使えない。(どんだけ読むつもりだ…)
  • Phobos には文字コードフィルタがない… 正直困る。

標準入出力

(2005/7/2 変更)

  • std.cstream に CFile クラス(FILE* 型のラッパクラス)で din, dout, derr が定義されている。
    • std.cstream の stdin, stdout, stderr は deprecated になった。std.cstream の din, dout, derr を使うこと。
    • これに伴い、std.c.stdio と std.stream との conflict が解決。
    • std.c.stdio に FILE* 型として stdin, stdout, stderr が定義されているが、これは通常使わない。(生の C のファイルポインタ)

単純に入力をそのまま出力するプログラム

import std.cstream;
int main(char[][] args)
{
    while (!din.eof())
    {
        char[] line = din.readLine();
        dout.writeLine(line);
    }
    return 0;
}

UTF-8 で入出力される点に注意。Shift JIS を通すと途中でこける。

D言語にない機能

  • 文字列中の変数展開、文字列中の式展開 (Perl, Ruby などにはある。)
    • Perl の例。$var を展開する。
      "blah $var blahblah"
  • 言語埋め込みの正規表現
    • 正規表現ライブラリ(std.regexp)は標準で存在する。
    • Perl からの移植は結構めんどくさい。
  • 動的なクラスロード
    • ランタイムで動的に処理を変えたいような場合、CGI のように別プロセスで立ち上げるか、DLL を読み込むことになる。(DLL はOS依存性高し)
  • 多重継承
    • C++ からの移植で困るかもしれない。C++ でも禁忌扱いなのであまり気にしなくてもいいかも。
  • プリプロセッサ

Cプログラマが気をつける点

C++プログラマが気をつける点

  • まずはこれ http://www.kmonos.net/alang/d/cpptod.html
  • 抽象クラスはクラスに abstract 属性を付けるか、abstract 属性の付いたメソッドをクラスに置く。
  • virtual の指定はない。全部 virtual 扱い。

C/C++/Javaプログラマが気をつける点

  • インスタンスの存在判定に null との比較(if (x == null), if (x != null))は使えない。
    • is 演算子を使うか、!演算子を使うか、素のままで評価する。(if (x is null), if (x !is null), if (!x), if (x))

Javaプログラマが気をつける点

  • if (x instanceof Class) は if ((cast(Class) x) !is null) となる。if (cast(Class) x) だけでもいいかも。
    • is(x : Class) は「コンパイル時評価」なので要注意。一般にテンプレートとかで使う。
  • リフレクションはない。リフレクションに頼ったコードは見直しが必要。(というか、Java は安易にリフレクション使いすぎ…)
  • Java の == 演算子によるインスタンスの同一性判定は、D言語では is 演算子、!is 演算子を使う。
  • Java の Object.equals(Object) (同値判定)に相当するのは == 演算子。

Socket

  • InternetHost クラス, InternetAddress クラスが IPv4 固定。時代遅れの感が否めない。
  • 元々 IPv6 は、せいぜい「利用可/不可」を事前に設定した後は、IPv4 と透過的に扱えるべきだと思うのだが…

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2013-07-14 (日) 22:13:52 (1591d)