開発環境と言語の選択

ここんところDelphiとは全く縁のない生活をしていて、C++でコードを書いている。

Delphiで書いていたときの苦い思い出として、メモリリークを修正するのにすごく時間がかかった*1、ということがあった。

それ以来ぼくはポインタが嫌いになり、メモリリークチェッカの早期導入と極力ポインタを使わないようなコーディングをこころがけるようになった*2

そして現在、C++でも相変わらず非常にポインタがきらいなので、ほとんどを値渡しと参照のみで書くが、JavaC#のような感覚でインスタンスを参照出来ないのがもどかしい。それにスクリプト言語に比べて、同じことをやるために書かなければならないコードが多くて疲れる*3

そもそもC++で書いているのは、極力小さなWin32ネイティブな実行イメージを作りたいからだ。この条件で、もっと思うがままにコードを書くにはどうすればいいのだろうか?


そこで考えたのが、スクリプト言語インタプリタを搭載することだった。そのときは、Luaを使うことにした。数あるスクリプト言語からLuaを選んだ理由は、実績*4と組み込みやすさだ。

実際に使ってみても、使い勝手のよいテーブルと、無名関数は僕をひきつけてやまなかった。しばらくLuaでコードを書き続けて、5000行を超える辺りからメンテナンスをするのが難しいことに気づいた。SciTEというエディタがコード補完をカスタマイズできて便利だったが、
静的にルールを設定する必要があるし、もともとIDEじゃないので現在のコードを解析してルールを作ってくれたりしないのが不満だった。

そこで、組み込みやすくて周辺ツールが充実している言語を探している。そうなると当然メジャーな言語になってくるだろうと思い、次の言語をチェックしている。

  1. Python
  2. Perl
  3. Ruby
  4. Java(スクリプト言語じゃないけど)

Pythonは試しに組み込んでみたが、ライブラリの利用なしでやるとものすごく簡単だった。

[プログラミング]自分のプログラムでPythonスクリプトを実行できるようにしよう

このへんを参考にしてやってみた。

#include <Python.h>

int main( int argc, char *argv[] )
{
	PyObject *pName, *pModule, *pDict, *pFunc;
	PyObject *pArgs, *pValue;

	int i;

	if ( argc < 3 ) {
		fprintf( stderr,"Usage: call pythonfile funcname [args]\n" );
		return 1;
	}

	Py_Initialize();
	pName = PyString_FromString( argv[1] );
	/* Error checking of pName left out */

	pModule = PyImport_Import( pName );
	Py_DECREF(pName);

	if ( pModule != NULL ) {
		pFunc = PyObject_GetAttrString(pModule, argv[2]);
		/* pFunc is a new reference */

		if (pFunc && PyCallable_Check(pFunc)) {
			pArgs = PyTuple_New(argc - 3);
			for (i = 0; i < argc - 3; ++i) {
				pValue = PyInt_FromLong(atoi(argv[i + 3]));
				if (!pValue) {
					Py_DECREF(pArgs);
					Py_DECREF(pModule);
					fprintf(stderr, "Cannot convert argument\n");
					return 1;
				}
				/* pValue reference stolen here: */
				PyTuple_SetItem(pArgs, i, pValue);
			}
			pValue = PyObject_CallObject(pFunc, pArgs);
			Py_DECREF(pArgs);
			if (pValue != NULL) {
				printf("Result of call: %ld\n", PyInt_AsLong(pValue));
				Py_DECREF(pValue);
			}
			else {
				Py_DECREF(pFunc);
				Py_DECREF(pModule);
				PyErr_Print();
				fprintf(stderr,"Call failed\n");
				return 1;
			}
		}
		else {
			if (PyErr_Occurred())
				PyErr_Print();
			fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
		}
		Py_XDECREF(pFunc);
		Py_DECREF(pModule);
	}
	else {
		PyErr_Print();
		fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
		return 1;
	}
	Py_Finalize();
	return 0;
}
<||
コンパイルして作ったプログラムがpytest.exeだとすると
>>
pytest スクリプトファイル名 関数名
<<

*1:当時はスキルが今よりもずっとずっと低かったということもある、多分、プログラミングをはじめて二年目くらいのときだ

*2:Delphiだと僕が知っているのはDelphiXの作者でTMPEGEncの作者の堀さんが作ったMemCheck.pasくらいです

*3:Code Complete 第4章 「コンストラクションにおける重要な決断」によると、一行のコードで伝えることの出来る命令数の比率はC++:Perl = 2.5:6 らしい

*4:精密にそれぞれを比較・検討したわけではないが