【Kotlin】インラインクラス（stable）リファレンス翻訳

2021-05-05、Kotlin 1.5.0 がリリースされました。

インラインクラスがようやく stable になったので
Kotlin 公式リファレンスの「Inline classes」を翻訳してみました。

https://kotlinlang.org/docs/inline-classes.html

なお原文は [Apache 2 license](https://github.com/JetBrains/kotlin-web-site/blob/master/LICENSE) の下で公開されています。

以下翻訳です。

---

<!-- # Inline classes -->

# インラインクラス

<!--
Sometimes it is necessary for business logic to create a wrapper around some type. However, it introduces runtime 
overhead due to additional heap allocations. Moreover, if the wrapped type is primitive, the performance hit is terrible, 
because primitive types are usually heavily optimized by the runtime, while their wrappers don't get any special treatment. 
-->

ビジネスロジックにおいて何らかの型に対するラッパーを作成することが必要な場合があります。
しかしそれは追加のヒープ割り当てによる実行時のオーバーヘッドをもたらします。
さらに、ラップされる型がプリミティブの場合、パフォーマンスの低下は恐るべきものになります。プリミティブ型は通常であればランタイムによって大きく最適化されますが、そのラッパーは特別な扱いを受けないからです。

<!--
To solve such issues, Kotlin introduces a special kind of class called an _inline class_. 
Inline classes are a subset of [value-based classes](https://github.com/Kotlin/KEEP/blob/master/notes/value-classes.md). They don't have an identity and can only hold values.
-->

このような問題を解決するため、Kotlin は_インラインクラス_と呼ばれる特別な種類のクラスを導入します。
インラインクラスは[値ベースのクラス](https://github.com/Kotlin/KEEP/blob/master/notes/value-classes.md)のサブセットです。
これらはアイデンティティーを持たず、ただ値を保持するだけです。

<!--
To declare an inline class, use the `value` modifier before the name of the class:
-->

インラインクラスを宣言するには、クラス名の前に `value` 修飾子を付けます：

<!--
```kotlin
value class Password(private val s: String)
```
-->

```kotlin
value class Password(private val s: String)
```

<!--
To declare an inline class for the JVM backend, use the `value` modifier along with the `@JvmInline` annotation before the class declaration: 
-->

JVM バックエンド向けにインラインクラスを宣言するには、`value` 修飾子を `@JvmInline` アノテーションとともにクラス宣言の前に付けます：

<!--
```kotlin
// For JVM backends
@JvmInline
value class Password(private val s: String)
```
-->

```kotlin
// JVM バックエンド向け
@JvmInline
value class Password(private val s: String)
```

<!---
> :warning: The `inline` modifier for inline classes is deprecated.
-->

> :warning: インラインクラスに対する `inline` 修飾子は非推奨です。

<!--
An inline class must have a single property initialized in the primary constructor. At runtime, instances of the inline 
class will be represented using this single property (see details about runtime representation [below](#representation)):
-->

インラインクラスはプライマリコンストラクタで初期化される単一のプロパティを持たねばなりません。
実行時には、インラインクラスのインスタンスはこの単一のプロパティを用いて表現されます（実行時の表現の詳細については[後述](#表現)）：

<!--
```kotlin
// No actual instantiation of class 'Password' happens
// At runtime 'securePassword' contains just 'String'
val securePassword = Password("Don't try this in production") 
```
-->

```kotlin
// クラス 'Password' は実際にはインスタンス化されない。
// 実行時には 'securePassword' は単に 'String' を持つ。
val securePassword = Password("これを製品で試してはならない") 
```

<!--
This is the main feature of inline classes, which inspired the name *inline*: data of the class is *inlined* into its 
usages (similar to how content of [inline functions](inline-functions.md) is inlined to call sites).
-->

これはインラインクラスの主要な機能であり、*インライン* という名前の由来です：クラスのデータはそれが使用される場所に*インライン化*されます（[インライン関数](https://kotlinlang.org/docs/inline-functions.html)の内容がその呼び出し元にインライン化されるのと同様に）。

<!-- ## Members -->

## メンバ

<!--
Inline classes support some functionality of regular classes. In particular, they are allowed to declare properties and 
functions, and have the `init` block:
-->

インラインクラスは通常のクラスのいくつかの機能をサポートします。
特に、プロパティと関数を宣言することと、`init` ブロックを持つことが可能です：

<!--
```kotlin
@JvmInline
value class Name(val s: String) {
    init {
        require(s.length > 0) { }
    }

    val length: Int
        get() = s.length

    fun greet() {
        println("Hello, $s")
    }
}

fun main() {
    val name = Name("Kotlin")
    name.greet() // method `greet` is called as a static method
    println(name.length) // property getter is called as a static method
}
```
-->

```kotlin
@JvmInline
value class Name(val s: String) {
    init {
        require(s.length > 0) { }
    }

    val length: Int
        get() = s.length

    fun greet() {
        println("Hello, $s")
    }
}

fun main() {
    val name = Name("Kotlin")
    name.greet() // メソッド `greet` はスタティックメソッドとして呼ばれる
    println(name.length) // プロパティのゲッターはスタティックメソッドとして呼ばれる
}
```

<!--
Inline class properties cannot have [backing fields](properties.md#backing-fields). They can only have simple computable 
properties (no `lateinit`/delegated properties).
-->

インラインクラスのプロパティは[バッキングフィールド](https://kotlinlang.org/docs/properties.html#backing-fields)を持てません。
持てるのは単純な計算可能プロパティだけです（`lateinit`／委譲プロパティも不可）。

<!-- ## Inheritance -->

## 継承

<!--
Inline classes are allowed to inherit from interfaces:
-->

インラインクラスはインターフェイスを継承することができます。

<!--
```kotlin
interface Printable {
    fun prettyPrint(): String
}

@JvmInline
value class Name(val s: String) : Printable {
    override fun prettyPrint(): String = "Let's $s!"
}

fun main() {
    val name = Name("Kotlin")
    println(name.prettyPrint()) // Still called as a static method
}
```
-->

```kotlin
interface Printable {
    fun prettyPrint(): String
}

@JvmInline
value class Name(val s: String) : Printable {
    override fun prettyPrint(): String = "Let's $s!"
}

fun main() {
    val name = Name("Kotlin")
    println(name.prettyPrint()) // これもスタティックメソッドとして呼ばれる
}
```

<!--
It is forbidden for inline classes to participate in a class hierarchy. This means that inline classes cannot extend 
other classes and must be `final`.
-->

インラインクラスがクラス階層に参加することはできません。
これは、インラインクラスは他のクラスを継承することができず、また `final` でなければならないということです。

訳注：
暗黙的に `final` となり、インラインクラスを継承したクラスを定義できない。

<!-- ## Representation -->

## 表現

<!--
In generated code, the Kotlin compiler keeps a *wrapper* for each inline class. Inline class instances can be represented 
at runtime either as wrappers or as the underlying type. This is similar to how `Int` can be 
[represented](basic-types.md#numbers-representation-on-the-jvm) either as a primitive `int` or as the wrapper `Integer`.
-->

生成されたコードにおいて、Kotlin コンパイラは各インラインクラスの*ラッパー*を維持します。
インラインクラスのインスタンスは実行時にラッパーとしても元の型としても表すことができます。
これは `Int` がプリミティブな `int` としてもラッパーである `Integer` としても[表す](https://kotlinlang.org/docs/basic-types.html#numbers-representation-on-the-jvm)ことができるのと同様です。

<!--
The Kotlin compiler will prefer using underlying types instead of wrappers to produce the most performant and optimized code. 
However, sometimes it is necessary to keep wrappers around. As a rule of thumb, inline classes are boxed whenever they 
are used as another type.
-->

Kotlin コンパイラはラッパーではなく元の型を使うことで最もパフォーマンスが高く最適化されたコードを生成しようとします。
しかし、ラッパーが必要になることもあります。
経験的には、インラインクラスは他の型として使われる際には常にボックス化（boxed）されます。

訳注：
ボックス化（boxed）はラッパーのインスタンスに変換されること。非ボックス化（unboxed）は元の型の値に変換されること。

<!--
```kotlin
interface I

@JvmInline
value class Foo(val i: Int) : I

fun asInline(f: Foo) {}
fun <T> asGeneric(x: T) {}
fun asInterface(i: I) {}
fun asNullable(i: Foo?) {}

fun <T> id(x: T): T = x

fun main() {
    val f = Foo(42) 
    
    asInline(f)    // unboxed: used as Foo itself
    asGeneric(f)   // boxed: used as generic type T
    asInterface(f) // boxed: used as type I
    asNullable(f)  // boxed: used as Foo?, which is different from Foo
    
    // below, 'f' first is boxed (while being passed to 'id') and then unboxed (when returned from 'id') 
    // In the end, 'c' contains unboxed representation (just '42'), as 'f' 
    val c = id(f)  
}
```
-->

```kotlin
interface I

@JvmInline
value class Foo(val i: Int) : I

fun asInline(f: Foo) {}
fun <T> asGeneric(x: T) {}
fun asInterface(i: I) {}
fun asNullable(i: Foo?) {}

fun <T> id(x: T): T = x

fun main() {
    val f = Foo(42) 
    
    asInline(f)    // 非ボックス化される: Foo 自身として使用される
    asGeneric(f)   // ボックス化される: ジェネリックな型 T として使用される
    asInterface(f) // ボックス化される: 型 I として使用される
    asNullable(f)  // ボックス化される: Foo とは異なる Foo? として使用される
    
    // 以下では、'f' は最初はボックス化され（'id' に渡されるとき）、その後非ボックス化される（'id' から返されるとき）。 
    // 最後に、'c' は非ボックス化された表現（単なる '42'）を保持する。'f' のように。
    val c = id(f)  
}
```

<!--
Because inline classes may be represented both as the underlying value and as a wrapper, [referential equality](equality.md#referential-equality) 
is pointless for them and is therefore prohibited.
-->

インラインクラスは元の値とラッパーのどちらとしても表現される可能性があります。それゆえ[参照の等価性](https://kotlinlang.org/docs/equality.html#referential-equality)はインラインクラスにとっては意味がなく、使用が禁止されています。

訳注：
演算子 `===` および `!==` は使えないということ。

<!-- ### Mangling -->

### マングリング（名前修飾）

<!--
Since inline classes are compiled to their underlying type, it may lead to various obscure errors, for example unexpected platform signature clashes:
-->

インラインクラスはその元の型としてコンパイルされるため、例えば予期せぬプラットフォーム署名の衝突などの、様々な不明瞭なエラーを引き起こす可能性があります：

<!--
```kotlin
@JvmInline
value class UInt(val x: Int)

// Represented as 'public final void compute(int x)' on the JVM
fun compute(x: Int) { }

// Also represented as 'public final void compute(int x)' on the JVM!
fun compute(x: UInt) { }
```
-->

```kotlin
@JvmInline
value class UInt(val x: Int)

// JVM では 'public final void compute(int x)' として表現される
fun compute(x: Int) { }

// こちらも JVM では 'public final void compute(int x)' として表現される！
fun compute(x: UInt) { }
```

<!--
To mitigate such issues, functions using inline classes are *mangled* by adding some stable hashcode to the function name. 
Therefore, `fun compute(x: UInt)` will be represented as `public final void compute-<hashcode>(int x)`, which solves the clash problem.
-->

このような問題を減らすため、インラインクラスを使用する関数は関数名に安定したハッシュコードを追加することで*マングル*されます。
それゆえ、`fun compute(x: UInt)` は `public final void compute-<hashcode>(int x)` と表わされることになり、衝突問題は解決されます。

<!--
> :information_source: The mangling scheme has been changed in Kotlin 1.4.30. 
> Use the `-Xuse-14-inline-classes-mangling-scheme` compiler flag to force the compiler to use the old 1.4.0 mangling scheme and preserve binary compatibility.
-->

> :information_source: マングリングの仕組みは Kotlin 1.4.30 で変更されました。
> コンパイラフラグ `-Xuse-14-inline-classes-mangling-scheme` を使用することで、コンパイラに古い 1.4.0 のマングリングの仕組みを使用させ、バイナリの互換性を保つことができます。

<!-- ### Calling from Java code -->

### Java コードからの呼び出し

<!--
You can call functions that accept inline classes from Java code. To do so, you should manually disable mangling:
add the `@JvmName` annotation before the function declaration:
-->

インラインクラスを受け取る関数を Java のコードから呼び出すことができます。
そのためには手動でマングリングを無効化しなければなりません：
関数宣言の前に `@JvmName` アノテーションを付けてください：

<!--
```kotlin
@JvmInline
value class UInt(val x: Int)

fun compute(x: Int) { }

@JvmName("computeUInt")
fun compute(x: UInt) { }
```
-->

```kotlin
@JvmInline
value class UInt(val x: Int)

fun compute(x: Int) { }

@JvmName("computeUInt")
fun compute(x: UInt) { }
```

<!-- ## Inline classes vs type aliases -->

## インラインクラス 対 型エイリアス

<!--
At first sight, inline classes seem very similar to [type aliases](type-aliases.md). Indeed, both seem to introduce 
a new type and both will be represented as the underlying type at runtime.
-->

一見、インラインクラスは[型エイリアス](https://kotlinlang.org/docs/type-aliases.html)にとてもよく似ています。
実際どちらも、新しい型を導入するように見え、実行時には元の型で表されます。

<!--
However, the crucial difference is that type aliases are *assignment-compatible* with their underlying type (and with 
other type aliases with the same underlying type), while inline classes are not.
-->

しかし決定的な違いがあります。型エイリアスはその元の型（および同じ元の型を持つ別の型エイリアス）と*代入の互換性*がありますが、インラインクラスはそうではありません。

<!--
In other words, inline classes introduce a truly _new_ type, contrary to type aliases which only introduce an alternative name 
(alias) for an existing type:
-->

言い換えると、既存の型に別名（エイリアス）を導入するだけの型エイリアスとは対照的に、インラインクラスは真に_新しい_型を導入します。

<!--
```kotlin
typealias NameTypeAlias = String

@JvmInline
value class NameInlineClass(val s: String)

fun acceptString(s: String) {}
fun acceptNameTypeAlias(n: NameTypeAlias) {}
fun acceptNameInlineClass(p: NameInlineClass) {}

fun main() {
    val nameAlias: NameTypeAlias = ""
    val nameInlineClass: NameInlineClass = NameInlineClass("")
    val string: String = ""

    acceptString(nameAlias) // OK: pass alias instead of underlying type
    acceptString(nameInlineClass) // Not OK: can't pass inline class instead of underlying type

    // And vice versa:
    acceptNameTypeAlias(string) // OK: pass underlying type instead of alias
    acceptNameInlineClass(string) // Not OK: can't pass underlying type instead of inline class
}
```
-->

```kotlin
typealias NameTypeAlias = String

@JvmInline
value class NameInlineClass(val s: String)

fun acceptString(s: String) {}
fun acceptNameTypeAlias(n: NameTypeAlias) {}
fun acceptNameInlineClass(p: NameInlineClass) {}

fun main() {
    val nameAlias: NameTypeAlias = ""
    val nameInlineClass: NameInlineClass = NameInlineClass("")
    val string: String = ""

    acceptString(nameAlias) // OK: 元の型の代わりにエイリアスを渡す
    acceptString(nameInlineClass) // OK ではない: 元の型の代わりにインラインクラスを渡すことはできない

    // 逆もまた然り:
    acceptNameTypeAlias(string) // OK: エイリアスの代わりに元の型を渡す
    acceptNameInlineClass(string) // OK ではない: インラインクラスの代わりに元の型を渡すことはできない
}
```

---

以上翻訳でした。

誤訳や分かりにくいところがありましたら
ご指摘いただけると幸いです。

／以上