捨てたい null

static String lastComponent(String url) {
  if (url == null) {
    return "";
  } else {
    final String component = android.net.Uri.parse(url).getLastPathSegment();
    return component != null ? component : "";
  }
}

というコードを書いてレビューに回したところ parse が null を返すこともあるので null チェックを入れてくださいと返ってきた。

そのまま指示を飲むなら、こんな感じになるのか?

static String lastComponent(String url) {
  if (url == null) {
    return "";
  } else {
    final android.net.Uri uri = android.net.Uri.parse(url);
    final String component = uri != null ? uri.getLastPathSegment() : null;
    return component != null ? component : "";
  }
}

ああ、なんという💩(うんこ)ード……!

とりあえず以下に変更して再レビューにまわした。

static String lastComponent(String url) {
  try {
    final String component = android.net.Uri.parse(url).getLastPathSegment();
    return component != null ? component : "";
  } catch (NullPointerException e) {
    return "";
  }
}

けれど、やっぱりどうにも気に入らない。末尾でしている null チェック、これがどうにも美しくない。

* * *

こうすれば、まあ許容範囲 ……かな?

static String lastComponent(String url) {
  try {
    return android.net.Uri.parse(url).getLastPathSegment().toString();
  } catch (NullPointerException e) {
    return "";
  }
}

でも末尾の toString() がトリッキー。もともと Uri#getLastPathSegment() は String を返す。それをわざわざ toString() するのはなぜ? という疑念をいだき削除するメンテナーが将来、でてくる気がする。(null アクセスして例外を吐かせて catch 節に合流させるためなんだけれどね……)

だったらコメント書け、あるいは、素直に null チェックしろ、なんだろう。(どちらも嫌だ)

* * *

どんな型にでもマッチする null という値の存在が、どうにもイケていないんだと、最近の僕はおもう。

* * *

計算の失敗の可能性を表現するために null を使うのは、結局その呼び手に if 分岐のペナルティを課している。パイプラインはストールして投機実行は捨てられる。

だったら計算の失敗はすべからく例外で表現する、でよいのでは?

あるいは Haskell の Either のようなパターンマッチで解決を図る。

* * *

失敗の可能性は、掛け算で分岐を増やしていく。
分岐に処理の本筋が埋もれて可読性が損なわれる。

マルチスレッド、
コールバック、
分岐。

これら処理の複雑さを、
ある時はズームアウトして概観し、
ある時はズームインして詳細に調べる。

そういうコード開発を、できないものだろうかなあ……。

この記事が気に入ったらサポートをしてみませんか?