この記事は、

jugad2 - Vasudev Ram on software innovation: Porting the text pager from Python to D (DLang)

を自分用に翻訳したものを 許可を得て 公開するものである。 誤字や誤訳などを見つけたら今すぐ Pull requestだ!


$ tp file.txt
$ dir /s | tp

数週間前、私はこのような記事を書きました:

tp, a simple text pager in Python

数日前、私はこのページャをPythonからD 言語として知られるDに移植しようと思いたち、そして実行しました。

DについてのWikipediaの記事にはこうあります:

C++のリエンジニアリングとして始まったものですが、Dは他の言語、特にJava、Python、Ruby、C#、やEiffelからもインスピレーションを得て、 Cのコア機能をリデザインした独自の言語です。

こちらがtp.dのコードです

/*
File: tp.d
Purpose: A simple text pager.
Version: 0.1
Platform: Windows-only.
May be adaptable for Unix using tty / termios calls.
Only the use of getch() may need to be changed.
Author: Vasudev Ram
Copyright 2017 Vasudev Ram
Web site: https://vasudevram.github.io
Blog: https://jugad2.blogspot.com
Product store: https://gumroad.com/vasudevram
Twitter: https://mobile.twitter.com/vasudevram
*/

import std.stdio;
import std.string;
import std.file;

extern (C) int getch();

void usage(string[] args) {
    stderr.writeln("Usage: ", args[0], " text_file");
    stderr.writeln("or");
    stderr.writeln("command_generating_text | ", args[0]);
}

void pager(File in_fil, int lines_per_page=12, char quit_key='q')
{
    assert (lines_per_page > 1);
    int line_count = 0;
    int c;
    foreach (line; in_fil.byLine()) {
        writeln(line);
        line_count++;
        if ( (line_count % lines_per_page) == 0) {
            stdout.flush();
            c = getch();
            if (c == 'q')
                break;
            else
                line_count = 0;
        }
    }
}

int main(string[] args) {

    int lines_per_page = 20;
    File in_fil;

    try {
        if (args.length > 2) {
            usage(args);
            return 1;
        }
        else {
            if (args.length == 2) {
                in_fil = File(args[1]);
            }
            else {
                in_fil = stdin;
            }
            pager(in_fil, lines_per_page, 'q');
        }
    } catch (FileException fe) {
        stderr.writeln("Caught FileException: msg = ", fe.msg);
    } catch (Exception e) {
        stderr.writeln("Caught Exception: msg = ", e.msg);
    }
    finally {
        in_fil.close();
    }
    return 0;
}

これをこのような一般的な方法でコンパイルし:

dmd tp.d

tp.exeを生成します。
これはPythonバージョンと同じように、2つの方法(ファイル呼び出し、または標準入力)いずれかで実行することができます。 これら2つの方法を、

tp tp.d

または

type tp.d | tp

ドッグフーディング(試用)することができます。

Pythonページャの場合(それ自身を実行するとき)のように、出力はそれ自身のソースプログラムと同じ為、ここには載せません。 これで、tpはless以下(tp is less than less)と言うことができます :) 1 2

このDページャを書いた後、私は簡単にPythonバージョンとの視覚的な比較をし、PythonとDバージョンと、 だいたい同じコードの全体の構造を見るのは興味深いものでした。 ファイルを開き(または標準入力を使い)、そこから各行を読み込み、ファイルを閉じ、キーボードから文字を得る。 すべてが振る舞いにおいてだいたい同じでした。 私の推察ではこれは少なくとも部分的にはPythonとDの両方共がCの遺産を共有しているためです。

実際、Dのコードでも:

foreach (line; in_fil.byLine()) {

少し斜め読みすれば、Pythonのコードとして読むことができます

for lin in fil.byLine()

必ずしも有効なPythonではないですが、byLineメソッドがfileオブジェクトにあるとすれば、読めないことはないです :)

興味のある方は、最近HNでDについての良いディスカッションがありました。こちらです:

The reference D compiler is now open source (dlang.org)

スレッドのタイトルにかかわらず、ライセンスの側面よりもD言語の機能についてのものです。

楽しんでください。


追記

これについてコメント:

for lin in fil.byLine()

必ずしも有効なPythonではないですが、byLineメソッドがfileオブジェクトにあるとすれば、読めないことはないです :)

もちろん、実際のPythonバージョンはもっとシンプルです:

for lin in in_fil:

これは、Dのそれがそうするように、lazyに(つまりオンデマンドに)ファイルの行をイテレーションします (Pythonのファイルオブジェクトがイテレータプロトコルで実装されているためです)。 言い換えると、メモリ上に一度にすべての行をロードしたりしません。 それぞれ要求があるたびに読み込みます。 だから速く、少ないメモリしか使いません。 Dバージョンにも同じことが言えます。

  1. less is moreのように 

  2. 2つの意味でLessです: 少ない機能と、短い名前。