Kotlin 0.12からKotlin 1.0.2にアップグレードした際にやったこと
Kotlinが1.0系になり、言語仕様が安定してきたとの事(後述)なので、
技術的な検証として、過去にKotlin 0.12で作ったアプリのKotlin 1.0.2へのアップグレード対応を試してみました。
コンパイラバージョンを切り替えたところ、1800個のコンパイルエラーが生じましたw
同じような境遇の方は少ないと思いますが、自分の事例を紹介します。
作業時間
上記の修正ですが、合計で3時間ほどの作業でコンパイルできるようになりました。
特に困難なものもありませんでした。
言語仕様の安定性について
公式のKotlin 1.0についての記事によると、
As of 1.0, we are committed to long-term backward compatibility of the language and its standard library (kotlin-stdlib):
と書いてあります。
0系から1系での追従でも大したことはなかったので、
今後のアップグレード追従についてはだいぶ楽観視できます。
import asでパッケージに別名を付けることができなくなった
jp.co.aaa.hogeネームスペースにHogeクラスが定義されている場合、
以前は下記のように書くことができました。
import jp.co.aaa.hoge as hoge
val x = hoge.Hoge()
しかし、このようにパッケージレベルで別名を付けることができなくなってしまいました。
上記のケースでは、Hoge自体に別名をつける必要があります。
import jp.co.aaa.hoge.Hoge as HogeHoge
val x = HogeHoge()
前者の方法であれば、jp.co.aaa.hogeの中にどのようなクラス名が入っていても、
別名のhogeさえ衝突しないのであれば、hoge.XXX
表記を使う限り衝突の心配が無かったのですが、
できなくなってしまい残念です。
Javaのクラスのメソッド名がKotlin風に変更された
java.util.Listで要素数を取得するsize()
メソッドは、
以前はlist.size()
のように呼ぶことができました。
今のKotlinではこれはsize
プロパティに変更されています。
呼び出し部分の丸括弧があるとコンパイルエラーになります。
このようにJavaのクラスのメソッド名が、
Kotlin風のメソッド名やプロパティに変更されました。
多くの変更がされているようですが、
僕が踏んだものを掲載します。
array.length()
->array.length
list.size()
->list.size
list.reverse()
->list.reversed()
list.remove()
->list.removeAt()
map.values()
->map.values
map.keySet()
->map.keys
map.entrySet()
->map.entries
entry.getKey()
->entry.key
entry.getValue()
->entry.value
あちこちで踏んでいたので修正には手間がかかりましたが、
修正後の仕様は綺麗なものばかりで、個人的には嬉しい修正です。
Mapの要素アクセスがnullableを返すようになった
上記のjavaライブラリの変更とも関係して、
Map<T>
の要素アクセスmap[key]
で以前はT!
を返していたものが、
T?
を返すようになりました。
T!
で来ている部分をT
で扱っていたケースでコンパイルエラーになります。
既存コードは既にテストされているものだったので、
マイグレーションとしては!!
を付けるだけの修正でした。
プロパティのバッキングフィールド名が変更された
以前はプロパティ名prop
に対して、$prop
というドル記号プレフィックスをつけたものが、
バッキングフィールドとして暗黙定義されていましたが、
field
という固定のキーワードに変更されました。
オペレータオーバーロードにoperatorキーワードが必要になった
以前はfun plus()
のようなメソッドを定義すれば、
それだけで+
演算子の実装を与えることができました。
それが、operator fun plus()
のように、
operator
キーワードの指定が必要になりました。
単項演算子の関数名が変更された
以前は単項演算子の+
と-
はplus
とminus
でした。
これがunaryPlus
とunaryMinus
に変わりました。
二項演算子はplus
のままです。
アノテーションに@
がついて、命名が変わった
suppress("UNUSED_PARAMETER")
などと書いていたところが、
@Suppress("UNUSED_PARAMETER")
と書くように変わりました。
@
がついてアッパーキャメルケースになり、Javaの仕様に近づきました。
変数名_
が予約された
クロージャ引数を読み捨てるようなケースで、
それをあらわすルールとして_
という変数名を使ったりしていましたが、
これがコンパイルエラーになりました。
Swiftで明示的に読み捨てる場合、let _ = ...
と、
_
を使うのでそれに似せて使っていたのですができなくなってしまいました。
ジェネリック関数の型パラメータ指定位置が変わった
ジェネリック関数の型パラメータの指定位置が変わりました。
以前は下記のように関数名とパーレンの間に書きました。
fun hoge<T>(arg: T)
現在は下記のようにfun
と関数名の間に書きます。
fun <T> hoge(arg: T)
前者の仕様だとswiftと同じ位置なのでわかりやすかったのですが、
変わってしまいました。
Javaクラスオブジェクトの取り出し方が変わった
以前のjava.lang.class<T>
の取り出しはjavaClass<T>()
でした。
これがT::class.java
に変わりました。
AndroidのIntent呼び出し箇所で使うため、
かなり多くの修正箇所がありました。
新しい仕様のほうが、
T::class
がKotlinでのクラスオブジェクトで、
それのjava
プロパティとしてJavaでのクラスオブジェクトが取り出せる形なので、
とてもわかりやすくなっていて良いと思います。
Deprecation警告の抑制アノテーションが変わった
以前はsuppress("DEPRECATED_SYMBOL_WITH_MESSAGE")
だったのですが、
@Suppress("DEPRECATION")
と変わりました。
わかりやすい名前になって良かったです。