プログラミング」カテゴリーアーカイブ

Haskell の Num クラスに対する不満

Haskell には Num という型クラスがあって、足し算とか掛け算の基本的な演算はここで定義されている。標準ライブラリで定義されているインスタンスとしては、 Int, Integer, Rational, Complex a などがある。

一言で言えば Num クラスは環っぽいものに対応するのだが、いろいろとアレな点がある。これを設計した人は、インスタンスとして整数、有理数、浮動小数点数、複素数くらいしか想定していないのではないか。 続きを読む

Picked up JAVA_TOOL_OPTIONS: を擬似的に消す

昔話

その昔、Mac OS X で java コマンドを起動するとターミナルが UTF-8 であってもメッセージがシフトJISで出力されて文字化けしてしまうという時代があった。

java コマンドの起動時に -Dfile.encoding=UTF-8 をつければ出力が UTF-8 になるが、毎回指定するのは面倒くさい。

そんな時、人々は JAVA_TOOL_OPTIONS という環境変数を -Dfile.encoding=UTF-8 に設定したものだ。

そうすれば、確かにメッセージは UTF-8 で出力される。されるのだが…。

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8

という余計なメッセージまで出力される。うるさい。

…というのは過去の話で、最近の Java を Mac 環境で使う分には JAVA_TOOL_OPTIONS を指定しなくても出力が UTF-8 になるので、特に問題はない。(確か、環境変数 LANG を読むはず)

2016年の話

残念なことだが、2016年にもなって、コマンドライン環境で UTF-8 以外のマルチバイトエンコーディング(シフトJISとか)が広く使われている環境が存在する。そういう環境に UTF-8 なターミナル(MinTTY とか)を用意してやっても、デフォルトでは java はシフトJISでメッセージを吐いてくる。したがって、そういう環境で java コマンドのメッセージの出力を UTF-8 にしたい場合は、 JAVA_TOOL_OPTIONS-Dfile.encoding=UTF-8 を指定する必要がある。

まあ、 UTF-8 以外のマルチバイトエンコーディングが広く使われている環境が存在するのは仕方がない。受け入れるしかない。しかし、Picked up JAVA_TOOL_OPTIONS: が出てくるのはなんとかしたい。

このメッセージの出力を抑制できないならば、せめて「見えないように」する方法があるのではないか。つまり、 Picked up JAVA_TOOL_OPTIONS: が印字された後に、空白文字で上書きする…!

つまり、こうだ:

JAVA_TOOL_OPTIONS=$'\r-Dfile.encoding=UTF-8\r                            \r'

$'ほにゃらら' というのは、 bash にエスケープ文字を解釈させる文法だ。この記事に関心を持つような人ならば何をやっているか分かるだろう。

キャリッジリターンとか言ってないで ANSI escape を駆使すれば空行すらなくせるかもしれないが、残念ながらそういうのはキャリッジリターン \r と違い、オプション解釈の際に空白として読み飛ばされない。

真面目な話

ドヤ顔でキャリッジリターンとか書いてみたものの、実際に使ってみると表示が崩れる場合が散見されるので、常用するのはやめたほうがよさそうである。

総合的に考えると、次のようなシェル関数を書いて対応するのがベストかと思われる。(シェルで単独で java を叩いた場合は Picked up … が表示されず、間接的に起動された場合は Picked up … が表示される。)あるいは、シェルスクリプトでラップしてやるという手も考えられる。

export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8
function java() {
    env JAVA_TOOL_OPTIONS="${JAVA_TOOL_OPTIONS/-Dfile.encoding=UTF-8/}" java -Df
ile.encoding=UTF-8 "$@"
}
function javac() {
    env JAVA_TOOL_OPTIONS="${JAVA_TOOL_OPTIONS/-Dfile.encoding=UTF-8/}" "${JDK_P
ATH}/javac" -J-Dfile.encoding=UTF-8 "$@"
}

何をやっているかというと、 java という名前のシェル関数で、「環境変数 JAVA_TOOL_OPTIONS から “-Dfile.encoding=UTF-8” という文字列を削除」「java コマンドに -Dfile.encoding=UTF-8 オプションを渡す」ということをやっている。bash 以外のシェルでは違う書き方が必要になるだろう。

余談

余談だが、ドットネット系のプログラムは、コマンドプロンプトで chcp 65001 をすると出力が UTF-8 になるようだ。UTF-8 なターミナルから MSBuild とか csc とかを叩くときに覚えておくと良いだろう。(Windows の Java も GetConsoleOutputCP で出力文字コードを判断してくれれば良かったのだが…)

Windows で JDK のインストール先を取得

Windows に JDK を入れた時のインスートル先のディレクトリというのは、バージョンによって変わる。これを機械的に取得したい。

環境変数の類は設定されない(公式のマニュアルに、手動で設定する方法が書かれてるくらいだし)ようだが、レジストリを見ればパスを取得できる。

Stack Overflow の質問には reg コマンドを使った回答が付いているが、Windows の場合こういうのはバッチファイルで書くよりも WSH を使った方が文字列処理等がすっきりするだろう。

というわけで書いてみた。

var WshShell = WScript.CreateObject("WScript.Shell");
var JDKKey = "HKLM\\SOFTWARE\\JavaSoft\\Java Development Kit\\";
var CurrentVersion = WshShell.RegRead(JDKKey + "CurrentVersion");
var JavaHome = WshShell.RegRead(JDKKey + CurrentVersion + "\\JavaHome");
var JDKBin = JavaHome + "\\bin";
WScript.Echo(JDKBin);

このファイルを例えば showjdkpath.js という名前で保存して、 CScript /nologo showjdkpath.js と実行すれば、標準出力に javac の場所が出てくる。

Haxe の正規表現のターゲット環境による違い

Haxe で正規表現を使う際には、次のような問題点がある。

  • ターゲット環境によって正規表現の細かい文法が違う。
  • ターゲット環境によっては、Unicode の code point 単位ではなく、 UTF-16 の code unit 単位で正規表現のマッチングを行うものがある。JavaScript とか JavaScript とか ECMAScript 5 とか
    • この場合、 [\uD800-\uDBFF][\uDC00-\uDFFF] というようなパターンを書くなどして、サロゲートペアを自前で処理しないといけない。

また、Haxe に限らなくても、文字列で正規表現のパターンを記述するのには、次のような問題点がある。

  • 複雑な正規表現を文字列の形で直接ソースコードに書くのは、コードの読みやすさ的によろしくない。
  • 正規表現の文字列を動的に構築する場合も考えると、いろいろカオスになりそう。

そこで、正規表現のパターン文字列を構築する Haxe のライブラリを作ることを考える。ライブラリ側で環境の違いも吸収することにすれば良い。 続きを読む

Haxe を触ってみた感想

Haxe とは、プログラミング言語である。公式サイト

ちょっとだけ使ってみたので、感じたことを書きなぐっておく。

特徴

複数の言語にコンパイルできる(ターゲット一覧):

  • Flash (bytecode) / ActionScript
    • 言語仕様は ActionScript の影響を色濃く受けているっぽい
  • JavaScript
  • PHP
  • Java, C#, C++ などの静的言語

良いところ

  • 代数的データ型(enum)とパターンマッチ(switch 式/文)がある。
  • Haskell で言うところの newtype みたいなやつ(abstract)がある。
  • インライン関数がある。
    • 実行時コストを気にすることなく another level of indirection を導入できる。
    • 条件コンパイルと併用するといい感じに環境の違いを吸収できそう。
  • マクロがある。
    • 実際どの程度強力かは、あまり使い込んでいないので何とも…。

悪いところ

  • Java のように、すべての関数をクラスの中に書かないといけない。main 関数はどこかのクラスの static 関数で定義する。
    • Java のようにと言うか、直接的には ActionScript から受け継いだ仕様っぽい。
  • 型クラスや deriving がない。
  • 代数的データ型を == で比較できないのが地味に辛い(Haskell なら deriving Eq をやっておけば == で比較できる)。Type.enumEq は、中に enum じゃない物が入っていた場合 == で比較してしまうみたいなので、オブジェクトへの参照を含む enum どうしの比較が辛いことになる。
  • null の扱いがイマイチ。動的ターゲットと静的ターゲットによって微妙に違う。
    • Option<T> 型と Null<T> 型のどちらを使うか迷う。
    • NonNull<T> みたいなものが欲しい。
  • 標準ライブラリの細かい仕様が、ターゲットに依存する場合がある。具体的には正規表現の EReg
    • Write once, debug everywhere と言う感じ。
    • ターゲット依存の挙動を排除するために標準ライブラリの実装を肥大化させるか、ターゲット依存の挙動を許して標準ライブラリの実装をスリムにするかのトレードオフなので、やむを得ない面はある。
    • 条件コンパイル(#if#elseif#else#end)が使えるので、適宜切り分けるべし。
  • 簡単なデータ型を作る時に、クラス型anonymous struct 型か(enum 型か)悩む。
    • Static extension を使えば、 anonyomous struct 型や enum 型にもメソッドを追加できる。
    • 構築方法が new Hoge(33, 4) / {foo: 33, bar: 4} / Hoge(33, 4) という風に違うが、 abstract を使えば吸収できそう(全部 new Hoge の形で構築できるようになる、はず)。
    • 静的言語がターゲットの場合、 anonymous struct 型は効率が悪そうに見えるので避けるべきかもしれない。
    • 一方、 JavaScript がターゲットだとクラスよりも anonymous struct の方が良いのか…?と思ったり。

各ターゲットに関して

  • JavaScript
    • 等値比較を === ではなく == でやっているのがイケてない。null/undefined との比較ならともかく、数値とか文字列とかは === で良くないか。
  • C++
    • 動的言語って感じのソースコードを吐き出す。
      • クラスのメタデータ満載。名前(文字列)によるフィールドへのアクセスとか。
      • Structural subtyping や(C++ ではなく Haxe の)RTTI を使わない場合にこいつらを抑制する手段はないのか。
    • 行番号やスタックの変数の情報と思われるもの(HX_STACK_LINE, HX_STACK_VAR)はコンパイルオプションの -no-debug で抑制できる。
    • Null<Int>Dynamic になってる。
    • 全体的に、もっと静的言語っぽいソースコードを吐き出す余地はあると思う。

まあ、手書きのコードには敵わないにせよ、知らないターゲット言語でも「とりあえず動く」ものを吐き出せるというのはすごいと思う(null の扱いの違いや正規表現の非互換に目をつぶれば)。

Visual C++ での C99 complex

最近のVisual C++ではC99もある程度サポートしているらしい。

上記ブログによると、 complex.h の関数もサポートしているらしい。しかし、コンパイラーは _Complex 型をサポートしていない。_Complex 型をサポートしていないのに、 complex.h の関数をサポートしているとはどういうことか。一体、 complex.h の関数は何を受け取って何を返すのか。

確認のため、次のような簡単な C++ のプログラムを書いてみた。 続きを読む

wxWidgets をビルドする

wxWidgets とは、C++で作られたクロスプラットフォームGUIツールキットである。Windows, OS X, GTK+ などに対応している。商用版のある Q なんとかと比べて見劣りするとか言うんじゃないぞ

入手

開発中の最新版を入手しよう。wxWidgets のリポジトリは、現在 GitHub でホストされている。(ただし、Issue の管理は GitHub ではなく wxWidgets Trac を使っている。GitHub でのプルリクはできる)

https://github.com/wxWidgets/wxWidgets

続きを読む

C言語でなんちゃって2進数リテラル

こういうビットマップ(1ピクセルにつき1ビット)を、整数の配列としてC言語のソースコード中に埋め込みたい:

□□□□□
■■■■■
□■□■□
□■□■□
■□□■■
□□□□□

2進数リテラルがあればそれを使うという手があるが、残念ながらC言語には2進数リテラルがない(ちなみに、C++にはC++14から2進数リテラルが入った。また、独自拡張で2進数リテラルが使えるコンパイラーもある)。

というわけで、自分で作ることにした。要件としては

  • コンパイル時定数となる
  • 桁を空白で区切れる

がある。 続きを読む

C言語の可変長引数マクロで擬似オーバーロード

C99で導入されたプリプロセッサマクロの可変長引数を使って、引数の個数によるオーバーロードっぽいことをするメモ。

参考:

可変長引数の部分への実引数が0個というのはC言語の規格的にはナシなので、引数が0個の場合には対応しない。(幾つかのコンパイラでは引数が0個でも通るが…)

GCCの場合に0個の引数を処理したい場合、GCC拡張の , ## __VA_ARGS__ みたいなやつを使うといい感じになる。

VC++で

#define CHOOSE(a0,a1,...)
#define hoge(...) CHOOSE(__VA_ARGS__)

という風に書くと、 __VA_ARGS__ の部分が一つの引数(a0)として関数型マクロに渡ってしまうので、ここに書いたコードでは CHOOSECHOOSE2 という風にもう一段階噛ませている。

C11の _Generic とかを使えば引数の型によるオーバーロードもできそうだ。先例: