Kotlinコンバート時にブロックコメントが入れ子にできる仕様を知らなくて30秒くらいフリーズした話

こんにちは Android アプリエンジニアの大橋です。
最近、Javaのプロジェクトを Kotlin にコンバートをしていたのですが、コンバートで一瞬「え?」となってしまったことについて書いてみました。

Javaコードをコンバートしたらブロックコメントの様子がおかしい

コンバートしていてJavaでは普通に通ってるのに Kotlin だとコードが一生コメントアウトされてる! そんな事が起こりました。

Kotlin に詳しい人なら知っている常識なのかもしれませんが、Kotlin はコメントが入れ子にできる仕様らしい。

そして今回の問題。おそらく先人が残した気の利いたコメントです。
プロジェクトのコードを見せることができないので似たような形で載せています。

「...」は省略です。どんなものかについては突っ込まないでください。

/**
*  Kitkat(20)以下では ... /res/drawable/*.xml ... 指定できない。
*  本クラスを利用
*/
 class FilterableState {
 }

API19 までをサポートしていた際につけていたコメントでした。 コメントが閉じているように見えるのですが、class FilterableState のコードは全てコメントアウトされていました。
パッと見なんでコメントアウトされてるのか謎でした。

30秒くらい固まり/*.xml ... 指定できない。 ここでコメントアウトの入れ子になっていることがわかります。

なるほど!これは良い間違い探しですね。 入れ子は便利かもしれませんが、ふとした時になんで?になりかねないのでお気をつけください。

微妙に公式リファレンスに一文書いてありました。

Unlike Java, block comments in Kotlin can be nested.

Swift でも入れ子にできるらしい

社内情報ツールでこのことを書いたところ、iOS エンジニアの方から Swift でも同じようなことができるとのコメントをもらい、全く同じコードを Swift のコードに貼り付けたところ同じ仕様でした。公式リファレンスにも記述がありました。こちらの方がちょっと親切かも。

Nesting multiline comments is allowed, but the comment markers must be balanced.

比較的新しめの言語ではコメントの入れ子は結構できるみたいです。

使いどころを考える

  • コード選択してコメントアウトより差分が少なくなる /**/コメント付きのコードを複数まとめてコメントアウトしたい場合、Java では/**/のネストコメントが許されてないため//によるコメントアウトで全ての行が diff になりますが、Kotlin では/**/のネストコメントが許されているため/*と*/の2行の diff だけで済みます。
/**
* 仮の[arg]を持つ仮のメソッド1
*/
 fun firstMethod(arg: Object) {
 ...
 }

/**
* 仮の[arg]を持つ仮のメソッド2
*/
 fun secondMethod(arg: Object) {
 ...
 }

こういったコードをコメントアウト前から fun firstMethodからfun secondMethod の最後までをコメントアウトする場合。

/*
/**
* 仮の[arg]を持つ仮のメソッド1
*/
 fun firstMethod(arg: Object) {
 ...
 }

/**
* 仮の[arg]を持つ仮のメソッド2
*/
 fun secondMethod(arg: Object) {
 ...
 }
 */

上記のような形にできる。diff は/**/ だけになるかと思います。ドキュメンテーションコメントを書いている場合でもブロックコメントが書きやすくなるかもしれません。
とはいえ、コメントアウトせずに消すことも多いと思うので頻繁に使うかは謎です。

最後に

今回、たまたま Java ファイルを Kotlin にコンバートして起こった現象で、ブロックコメントの入れ子は意識して使うことが多いと思います。今回のようなことは稀なのかもしれません。
また、最近の若い人はプログラムのサンプルに hogehoge とか使わないどころか、何それと突っ込まれる可能性があるらしいですね。hogehoge でググったら出てきたので書き直しました。
hogehoge 使いの自分には苦しい世の中になりましたので今後も精進して参ります。