算譜王におれはなる!!!!

偏りはあると思うけど情報技術全般についてマイペースに書くよ。

Kotlin M9まとめ

昨日のエントリで話したPlatform Type以外のM9で改善された言語機能について紹介するよ。

Non-local returns

コードの通りです。 関数リテラル内でのreturnが出来るよって話。 このコードを実行すると「1」だけ表示される。

fun main(args: Array<String>) {
    invoke {
        println("1")
        return // M9より前ではコンパイルエラー
    }
 
    println("2")
}
 
inline fun invoke(f: () -> Unit) {
    f()
}

No more local object declarations

M9より前では関数内にオブジェクト宣言を置けた。

// M9より前
fun foo() {
    object Point {
        var x = 0.0
        var y = 0.0
    }
}

これがM9からダメになった。 代わりにオブジェクト式を使う。

// M9
fun foo() {
    // ↓コンパイルエラーになる
    // object Point {
    //     var x = 0.0
    //     var y = 0.0
    // }
 
    // オブジェクト式で代替
    val point = object {
        var x = 0.0
        var y = 0.0
    }
}

platformStatic

Java用にstaticメソッドを定義できるようになった! platformStaticというアノテーションを付けるだけ。

import kotlin.platform.platformStatic
 
object Foo {
    fun hoge() {}
    platformStatic fun fuga() {}
}
 
class Bar {
    class object {
        fun piyo() {}
        platformStatic fun hage() {}
    }
}

上記のKotlinで定義した関数はJavaで次のように呼び出せる。

// Java
Foo.INSTANCE$.hoge();
Foo.fuga();
 
Bar.OBJECT$.piyo();
Bar.hage();

platformName

Kotlinでは例えば下記のようなコードを書ける。 2つの同名の関数succがあるけど、引数がIntOptionalCharOptional。 これを同時に定義できて、呼び出し時も区別してくれる。すごい。

でもJavaではそんなことは無理なのでJava用に別名を付ける必要がある。 そこでplatformNameアノテーションを使う。これはJava用のメソッド名をパラメータに取る。

package sample
 
import java.util.Optional
import kotlin.platform.platformName
 
fun succ(n: Optional<Int>) = n.map { it + 1 }
 
platformName("succOfChar")
fun succ(c: Optional<Char>) = c.map { (it + 1).toChar() }
 
fun main(args: Array<String>) {
    println(succ(Optional.of(5)))   // => Optional[6]
    println(succ(Optional.of('K'))) // => Optional[L]
}
// Java
import sample.SamplePackage;
import java.util.Optional;
 
public class Java {
    public static void main(String[] args) {
        SamplePackage.succ(Optional.of(5));
        SamplePackage.succOfChar(Optional.of('K'));
    }
}

ちなみに何気なくOptional#mapを呼び出して関数リテラルを食わせてるけど、M9からSAM変換が改善されたみたい。

Private property accessors

コード見てもらえばわかると思う。

trait Foo {
    fun getFoo(): Int
}
 
// M9より前だとコンパイルエラー
class FooImpl(private val foo: Int): Foo {
    override fun getFoo(): Int = 0
}

Fooトレイトを継承したらばpublicgetFoo()を実装する義務を負うけど、これとprivateなプロパティfooが今までは競合して上手くいかなかった。でもM9からは大丈夫!