On Error Resume Next (解決編)
大抵は自分が間違えている
前回の記事でエラーを解決せずに全部投げてオチをつけてしまいましたが、片がついたのでメモを残します。
clear を呼べない問題
Point[]
型の変数 buf
に対して buf.clear
を呼ぶと cannot deduce で以下の通り怒られた問題について:
Error: template `object.clear` cannot deduce function from argument types `!()(Point[])` candidates are: `object.clear(T : Value[Key], Value, Key)(T aa)` `object.clear(T : Value[Key], Value, Key)(T* aa)`
ただのエラーメッセージ読め案件だったので恥ずかしいんですが、上記を読むとどうもobject
モジュールのclear
テンプレートを展開しようとして失敗していますね。
僕が呼びたいのは Point[]
型の clear
メソッドなんですけど……?
UFCS って obj.method(a, b, ...)
に合うシグネチャのメソッドが見つからなかったときに初めて method(obj, a, b, ...)
を探しに行くんじゃなかったんです?
しかし愚かなのは僕の方でした。
そうです、D言語の動的配列に clear
メソッドは存在しないのです。
clear
が存在するのは Appender
オブジェクトか std.container
モジュールに収められているコンテナオブジェクトだけです。
当然動的配列にもあるもんだと思っていた……。
というわけで、この問題の解決法は buf.clear
を以下の通り修正することです:
// 再代入する buf = []; // length プロパティは set 可能なのでこれでもよい buf.length = 0;
cannot deduce とか言われると推論のための情報が足りないのかと思ってしまうけど、そもそも呼ぶ対象を間違えているケースがあるのだと知りました。なるほどなあ。
SList!Point を使うと RE する問題
bufの型を
SList!Point
にするとbuf.clear
でもコンパイルが通ります。 通りますし、手元(DMD v2.083.0)でも動きますが、ジャッジサーバ(DMD v2.070.1)では全ケース RE になります。
こればっかりはソースをいくら睨んでも解決しないと思ったので、ジャッジサーバの環境を手元に入れました。 仮想環境組むの面倒だったんで、手元の環境一度アンインストールして古い実行環境を再インストールするとかいうよわよわムーブを見せつけてしまった。
余談ですが、アンインストーラを走らせたらD言語環境関連のあれこれがしっかりディスクから取り除かれるのに、なぜかD/dmd2/html/d/images/compiler-dmd.png
だけが残ったんですよ。
それがコイツなんですけど:
D言語くんは死んでなんかいない……今も君のディスクの中にいるよ……*1。
閑話休題。とあるコードが手元(DMD v2.083.0)では走るのにジャッジサーバ(DMD v2.070.1)では実行時に落ちるという話でした。 その問題のコードの抜粋がこちら:
SList!Point buf;
// 中略
buf.insert(Point(x, y));
こちらをジャッジサーバ環境で走らせると、なるほど確かに実行時エラーを吐きますね:
core.exception.AssertError@std\container\slist.d(57): Assertion failure
すると気になるのは std\container\slist.d(57)
です。ちょっと覗いてみます:
struct SList(T) { // ……中略…… private Node * _root; private void initialize() @trusted nothrow pure { if (_root) return; _root = cast (Node*) new NodeWithoutPayload(); } private ref inout(Node*) _first() @property @safe nothrow pure inout { assert(_root); // 57行目 return _root._next; } // ……中略…… }
_root
が null
なので怒られたらしいですね。
これ、もしや SList
が初期化されてないだけでは?
というわけで解決策は buf
変数を宣言時に初期化しておくことです:
auto buf = make!(SList!Point);
めでたしめでたし*2。
おわりに
ちょっとだけD言語くんと仲良くなれる兆しが見えたかもしれない。 それはそれとして、どうせ競プロのためにしか使わないなら手元のコンパイラのバージョンをジャッジサーバのものと揃えておくのが無難っぽいですね。