Slide 1

Slide 1 text

Kotlin言語仕様書への招待
 〜コードの「なぜ」を読み解く〜
 Kotlin Fest 2025 @東京コンファレンスセンター品川


Slide 2

Slide 2 text

🐾 1. 自己紹介 🐾
 2 はじめまして


Slide 3

Slide 3 text

▼ 名前 
 3 本田 雄亮
 ▼ 所属企業  
 LINE Digital Frontier株式会社
 ▼ Xアカウント  
 @yyh_gl


Slide 4

Slide 4 text

🐾 会社紹介 🐾
 4

Slide 5

Slide 5 text

『LINEマンガ』を開発しています📚
 みなさまのおかげで5500万DLを突破!
 2025年 第1四半期および第2四半期は
 日本のすべてのアプリのなかで収益ランキング1位を達成🥇
 5 LINE Digital Frontier株式会社


Slide 6

Slide 6 text

1. Kotlin言語仕様書の概要 2. 言語仕様書の読み方 3. 仕様解説 a. Type System & Built-in types b. Overload resolution 4. 「へぇ〜」な仕様紹介 5. まとめ 6 アジェンダ


Slide 7

Slide 7 text

本発表の資料作成にあたり
 貴重なアドバイスをいただいたJetBrains社のMarat Akhin氏、
 ならびに発表練習にお付き合いいただいたLINE Digital Frontier社の
 同僚の皆様に心より感謝申し上げます。
 (犬の絵を描いてくれた妻にも)
 
 
 I would like to thank Marat Akhin of JetBrains for his valuable advice
 for this presentation and my colleagues at LINE Digital Frontier
 for their support with the presentation practice.
 (Also, my wife for drawing the dog illustrations.)
 7 謝辞|Acknowledgments


Slide 8

Slide 8 text

本発表で使用するサンプルコード(Kotlin Playgroundのリンク)や
 参考資料のリンクはスライドのスピーカーノートに記載しています。
 お好きなタイミングでご参照ください。
 8 サンプルコードおよび参考資料
 PlaygroundがWebで提供されている言語大好き

Slide 9

Slide 9 text

🐾 2. Kotlin言語仕様書の概要 🐾
 9

Slide 10

Slide 10 text

言語仕様書はプログラミング言語の文法や動作といった言語仕様が
 記述されたドキュメント。
 様々なプログラミング言語で言語仕様書が公開されている。
 10 「言語仕様書」とは


Slide 11

Slide 11 text

Kotlin Language Specification(Kotlin言語仕様書)はKotlinの公式サイトで
 公開されている。
 → https://kotlinlang.org/spec
 
 内容はGitHubで管理されている。
 仕様策定から修正提案まで、誰でも参加可能。
 → https://github.com/Kotlin/kotlin-spec
 11 Kotlin Language Specification


Slide 12

Slide 12 text

Kotlinの公式サイトには、言語仕様書以外にもたくさんのドキュメントが
 存在する。
 チュートリアルに始まり、文法や標準ライブラリの説明など
 様々なドキュメントが用意されている。
 12 言語仕様書以外にも…
 内容かぶってない…?

Slide 13

Slide 13 text

Kotlin/kotlin-specリポジトリのREADMEに以下の記述がある。 
 原文:
 > This repository contains the specification of the Kotlin programming language, 
 > which describes how parts of the language should function in more detail, 
 > as compared to a more traditional user documentation on the Kotlin Website. 
 日本語訳:
 > このリポジトリにはプログラミング言語 Kotlinの仕様が含まれており、 
 > Kotlinの公式サイトにある従来のユーザードキュメントと比較して、 
 > 言語の各部分がどのように機能するかをより詳細に説明しています。 
 13 他ドキュメントとの違い
 言語仕様書はより詳細な仕様を知るさいに参照すべきドキュメント 


Slide 14

Slide 14 text

原文:
 > It would be most useful to those who are interested 
 > in how Kotlin works on a finer level and how its features interoperate, 
 > e.g., language enthusiasts, compiler writers and Kotlin power-users. 
 > However, if you are simply wondering, 
 > why some code you wrote works the way it does, 
 > this specification might help you get an answer to that. 
 日本語訳:
 > 言語仕様書は、Kotlinの詳細な動作や機能の相互運用に興味がある人々、 
 > 例えば、言語愛好家、コンパイラの開発者、Kotlinの上級ユーザーにとって最も有用です。 
 > しかし、単に自分が書いたコードがなぜそのように動作するのか疑問に思っている場合、 
 > この仕様書がその答えを見つけるのに役立つかもしれません。 
 14 みんなに読んでほしい言語仕様書


Slide 15

Slide 15 text

原文:
 > It would be most useful to those who are interested 
 > in how Kotlin works on a finer level and how its features interoperate, 
 > e.g., language enthusiasts, compiler writers and Kotlin power-users. 
 > However, if you are simply wondering, 
 > why some code you wrote works the way it does, 
 > this specification might help you get an answer to that. 
 日本語訳:
 > 言語仕様書は、Kotlinの詳細な動作や機能の相互運用に興味がある人々、 
 > 例えば、言語愛好家、コンパイラの開発者、Kotlinの上級ユーザーにとって最も有用です。 
 > しかし、単に自分が書いたコードがなぜそのように動作するのか疑問に思っている場合、 
 > この仕様書がその答えを見つけるのに役立つかもしれません。 
 15 みんなに読んでほしい言語仕様書
 プログラミング言語が好き、 Kotlinが好きという方は 一度読んでみることをおすすめします! 「こんな書き方できたんだ」 「こんな機能があったんだ」 新しい発見にきっと繋がるはずです

Slide 16

Slide 16 text

現在のKotlin言語仕様書は、v1.9までの内容に対応している。
 ※ 2025年11月1日時点の最新バージョンはv2.2
 
 
 Kotlin開発チームのリソースが足りておらず
 2系に対応した仕様書を作成できていない状況。
 https://github.com/Kotlin/kotlin-spec/issues/137
 16 Kotlin言語仕様書の注意点①


Slide 17

Slide 17 text

Kotlinは複数のプラットフォームをサポートするマルチプラットフォーム言語。
 Kotlinはv1.9時点では下記マルチプラットフォームへのコンパイルをサポート。
 ● JVM
 ● JavaScript
 ● Android
 v2.2時点では以下のプラットフォームもあわせてサポート。
 ● Wasm
 ● Scripting
 17 Kotlin言語仕様書の注意点②


Slide 18

Slide 18 text

Kotlin言語仕様書が対象としているのはKotlin/Core の部分。
 Kotlin/Coreはプラットフォームに関わらずほぼ同様に機能する
 Kotlinのコア部分。
 18 「ほぼ」…? Kotlin言語仕様書の注意点②


Slide 19

Slide 19 text

プラットフォームによっては仕様書と異なる実装が存在するので注意が必要。 
 16.1 Catching exceptionsには以下の記述がある。
 > the applicability check is subject to Kotlin runtime type information limitations and
 > may be dependent on the platform implementation of runtime type information, 
 > as well as the implementation of exception classes .
 > 適用性チェックはKotlinのランタイム型情報の制限の影響を受ける可能性があり、
 > プラットフォームのランタイム型情報の実装や例外クラスの実装に依存する場合があります 。
 
 
 本発表でサンプルコードを示すときは、
 基本的にJVMプラットフォームの仕様に準拠したコードを記載する。
 19 Kotlin言語仕様書の注意点②


Slide 20

Slide 20 text

🐾 言語仕様書の読み方 🐾
 20

Slide 21

Slide 21 text

文法を表現する方法はいくつかある。
 Kotlin言語仕様書は、文法の表現方法としてEBNFベースの表記法を採用。
 EBNFはプログラミング言語の文法を表現するための代表的な方法のひとつ。
 Goの言語仕様書でも採用されている。
 21 文法の表現


Slide 22

Slide 22 text

広く知られているfor文を例にEBNFベースの表記法を見る。
 22 例: for文の文法
 よく見るコードだ

Slide 23

Slide 23 text

for文をEBNFベースの表記法で表現すると以下のようになる。
 23 例: for文の文法


Slide 24

Slide 24 text

24 for文の表記法を読み解く
 ● {NL}:改行が0回以上繰り返される
 ● {annotation}:アノテーションが0回以上繰り返される
 ● (variableDeclaration | multiVariableDeclaration):
   variableDeclarationまたはmultiVariableDeclarationのどちらか
 ○ variableDeclaration:変数宣言 
 ○ multiVariableDeclaration:複数変数宣言 
 ● expression:式
 ● [controlStructureBody]:
   制御構造の本体が
   0個または1個


Slide 25

Slide 25 text

EBNFベースの表記法を例であげたfor文と比較しながら解説。
 25 for文の表記法を読み解く


Slide 26

Slide 26 text

省略可能な部分も省略せずにコードを書いてみる。
 26 for文の表記法を読み解く


Slide 27

Slide 27 text

EBNFは慣れないと読みづらい。
 
 とはいえ、生成AIを使えばEBNFベースの表記法をコードに高精度で
 変換してくれる。
 生成AIが出してくれたコードを参考にしつつEBNFベースの表記法を
 読み解いていけばよい。
 27 EBNFベースの表記法
 AI時代に感謝

Slide 28

Slide 28 text

🐾 言語仕様書の読み方 🐾
 28 もう少しだけ


Slide 29

Slide 29 text

仕様は数学的表現を使って説明されている。
 例えば、数学記号で言うと以下のものが登場する。
 ● ∀(全称記号)
 ○ 「すべての」という意味 
 ○ e.g. ∀x:P(x) は「すべてのxについてP(x)が真である」という意味 
 ● ∃(存在記号)
 ○ 「少なくともひとつは存在する」という意味 
 ○ e.g. ∃x:x²=4 は「x²=4が成り立つxが少なくともひとつは存在する」という意味 
 ● ∈(属する)
 ○ 「属する」という意味
 ○ e.g. x∈A は「xはAに属する」という意味 
 数学が苦手でも生成AIのサポートを受けながら読めば結構理解できる。
 29 あると良い知識


Slide 30

Slide 30 text

一部の仕様についてはKotlin公式サイトの他ドキュメントでも説明している。
 これらのドキュメントの方が初心者にもわかりやすい内容になっている。
 あわせて読むと理解が捗る。
 30 サポートドキュメント


Slide 31

Slide 31 text

🐾 ここまでの話を整理 🐾
 31

Slide 32

Slide 32 text

Kotlin言語仕様書は
 ● EBNFベースの表記法により文法を定義
 ● 数学的表現を使って仕様を説明
 難しい内容もあるが、生成AIや他の公式ドキュメントが理解を助けてくれる。
 
 次ページからは、EBNFベースの表記法や数学的表現を読み解くことで
 どういった知識を得ることができるのか紹介&解説。
 32 ここまでの話を整理


Slide 33

Slide 33 text

🐾 仕様解説 🐾
 33 言語仕様書の内容をいくつか共有


Slide 34

Slide 34 text

🐾 Type System & Built-in types 🐾
 34 型システム & 組み込み型


Slide 35

Slide 35 text

型を定義したとき、自分で実装した覚えのないequalsメソッドが
 使えるのはなぜ?
 35 疑問


Slide 36

Slide 36 text

Sampleクラスは暗黙的にkotlin.Anyを継承しており、
 kotlin.Anyで定義されたequalsメソッドを使っている。
 明示的に書けばこういうこと。
 36 答え


Slide 37

Slide 37 text

Kotlinの型システムにおいてkotlin.Anyは特殊な役割を持っており
 すべての非null型のスーパークラスである。
 (すべての非null型は暗黙的にkotlin.Anyを継承している)
 kotlin.Anyは以下のメソッドを提供することが仕様として決まっている。
 37 解説


Slide 38

Slide 38 text

さきほどのサンプルコードにおけるequalsメソッドは
 kotlin.Anyから継承した関数。
 実際、IDEやエディタでequalsメソッドの定義元を参照すると
 kotlin.Anyの定義に飛ぶ。
 38 解説


Slide 39

Slide 39 text

🐾 Overload resolution 🐾
 39 オーバーロード解決


Slide 40

Slide 40 text

オーバーロードに慣れ親しんでいる人からすれば当たり前の実行結果だが
 Kotlinはどのように実行する関数を判断している?
 40 疑問


Slide 41

Slide 41 text

Kotlinは以下のプロセスで実行する関数を選択。
 1. オーバーロード候補リスト(overload candidate set, OCS)を構築
 2. 1のリストの中から最も具体的な関数を選択
 
 
 「最も具体的な関数」……?
 41 答え
 ぼやぼやな関数 具体的な関数 ?

Slide 42

Slide 42 text

まずはイメージを掴むためにざっくりとした考え方を説明。
 charSequenceValおよびstringValという値について
 funcWithCharSequence関数はどちらの値も引数に取れる。
 (String型はCharSequenceインタフェースを満たす)
 ※実際はオーバーロード候補になりえないペアだがイメージとして例示
 42 最も具体的な関数の選択


Slide 43

Slide 43 text

一方でfuncWithString関数はstringValしか引数に取れない。
 本ケースにおいてfuncWithString関数はfuncWithCharSequence関数より
 具体的な関数であると言える。
 43 最も具体的な関数の選択


Slide 44

Slide 44 text

見方を変えると、関数間の転送が可能かどうかを見ているイメージ。
 funcWithString関数はfuncWithCharSequence関数に転送できるが
 逆はできない。
 このような状況におけるfuncWithString関数をより具体的であると判断。
 44 最も具体的な関数の選択


Slide 45

Slide 45 text

関数の具体性チェックは型制約を使用して行う。
 これから説明する型制約を構築し、検証することで
 どの関数が最も具体的であるかがわかる。
 まずは型制約の構築を見ていく。
 45 言語仕様書視点の「最も具体的な関数の選択」
 オーバーロード候補の 関数たちに関して型制約を構築 構築された型制約を検証 1 2

Slide 46

Slide 46 text

関数呼び出し時にデフォルト引数が使用されていない引数について
 "型がX₁~Xₙである関数F₁"および"Y₁~Yₙである関数F₂"を対象に
 ● Xₖ <: Yₖという制約を設定
 ○ A <: B:「AはBのサブタイプである」という意味 
 ○ 型XおよびYがbuilt-in integer types の場合は特別な制約が適用される 
 ○ 型パラメータに対する処理も別途あるが簡素化のため省略 
 ● 拡張関数については拡張対象(レシーバー)も引数として考え型制約に追加
 ● 宣言されている型制約を追加
 46 型制約の構築


Slide 47

Slide 47 text

構築された型制約を満たしている場合、
 F₁はF₂と同等またはそれ以上に具体的な関数であると判断できる。
 その後、型制約の検証はF₁とF₂を入れ替えた状態でも実施する。
 以上の検証の結果は次の3つのいずれかとなる。
 1. F₁はF₂よりも具体的な関数である
 2. F₁もF₂も他方より具体的な関数ではない
 3. F₁もF₂も他方より具体的な関数である
 47 型制約の検証結果


Slide 48

Slide 48 text

● 「1. F₁はF₂よりも具体的な関数である」場合: 
 ○ 2つの候補に関して、より具体的な関数が見つかったので追加の手順はない 
 
 ● 「2. F₁もF₂も他方より具体的な関数ではない」場合: 
 ○ 型パラメータを持たない関数の方がより具体的であると判断 
 
 ● 「3. F₁もF₂も他方より具体的な関数である」場合: 
 ○ 型パラメータを持たない関数の方がより具体的であると判断 
 ○ 各候補について関数呼び出し時にデフォルト引数が使われている数をカウントし 
 カウント数が少ない候補をより具体的であると判断 
 ○ 可変長引数を持たない候補はより具体的であると判断 
 
 ● それでも最終候補が決まらない場合: 
 ○ ラムダ式の戻り値型を使用して絞り込む 
 ○ それでも最終候補が決まらなければ「オーバーロードの曖昧性」として 
 コンパイルエラーとする
 48 オーバーロード候補を絞り込む追加の手順


Slide 49

Slide 49 text

49 最も具体的な関数の選択 例1


Slide 50

Slide 50 text

50 F₁およびF₂について構築される制約
 ● 󰢏 Boolean <: Any
 ● 󰢏 String <: String
 ● 󰢏 Int <: Number
 ● 󰢏 T <: K
 ● 󰢏 T <: Comparable ▶ 制約の検証結果:すべての制約を満たせる 
 最も具体的な関数の選択 例1


Slide 51

Slide 51 text

関数呼び出し時にデフォルト引数が使用されていない引数について
 "型がX₁~Xₙである関数F₁"および"Y₁~Yₙである関数F₂"を対象に
 ● Xₖ <: Yₖという制約を設定
 ○ A <: B:「AはBのサブタイプである」という意味 
 ○ 型XおよびYがbuilt-in integer types の場合は特別な制約が適用される 
 ○ 型パラメータに対する処理も別途あるが簡素化のため省略 
 ● 拡張関数については拡張対象(レシーバー)も引数として考え型制約に追加
 ● 宣言されている型制約を追加
 51 最も具体的な関数の選択 例1


Slide 52

Slide 52 text

F₁とF₂を入れ替えて構築される制約
 ● 󰢃 Any <: Boolean
 ● 󰢏 String <: String
 ● 󰢃 Number <: Int
 ● 󰢃 K <: T
 ● 󰢏 T <: Comparable ▶ 制約の検証結果:すべての制約を満たせない 
 52 最も具体的な関数の選択 例1


Slide 53

Slide 53 text

● F₁およびF₂について構築される制約は満たされている
 ● F₁とF₂を入れ替えて構築される制約は満たされていない
 以上より、F₁はF₂に転送可能だが、逆は不可能であることがわかる。
 したがって、F₁はF₂よりも具体的な関数であると判断できる。
 53 最も具体的な関数の選択 例1


Slide 54

Slide 54 text

54 最も具体的な関数の選択 例2


Slide 55

Slide 55 text

F₁およびF₂について構築される制約
 ● 󰢏 String <: T
 ● 󰢃 Any <: String
 ▶ 制約の検証結果:すべての制約を満たせない 
 55 最も具体的な関数の選択 例2


Slide 56

Slide 56 text

関数呼び出し時にデフォルト引数が使用されていない引数について
 "型がX₁~Xₙである関数F₁"および"Y₁~Yₙである関数F₂"を対象に
 ● Xₖ <: Yₖという制約を設定
 ○ A <: B:「AはBのサブタイプである」という意味 
 ○ 型XおよびYがbuilt-in integer types の場合は特別な制約が適用される 
 ○ 型パラメータに対する処理も別途あるが簡素化のため省略 
 ● 拡張関数については拡張対象(レシーバー)も引数として考え型制約に追加
 ● 宣言されている型制約を追加
 56 最も具体的な関数の選択 例2


Slide 57

Slide 57 text

F₁とF₂を入れ替えて構築される制約
 ● 󰢃 T <: String
 ● 󰢏 String <: Any
 ▶ 制約の検証結果:すべての制約を満たせない 
 57 最も具体的な関数の選択 例2


Slide 58

Slide 58 text

● F₁およびF₂について構築される制約は満たされていない
 ● F₁とF₂を入れ替えて構築される制約は満たされていない
 F₁およびF₂についてオーバーロード候補を1つに絞ることができない。
 この場合、型パラメータを持たない関数をより具体的であると判断する 。
 したがって、F₁がF₂よりも具体的な関数であると判断できる。
 58 最も具体的な関数の選択 例2


Slide 59

Slide 59 text

59 最も具体的な関数の選択 例3


Slide 60

Slide 60 text

F₁およびF₂について構築される制約
 ● 󰢏 String <: String
 デフォルト引数は考慮しないので上記1つの制約だけとなる。
 ▶ 制約の検証結果:すべての制約を満たせる 
 60 最も具体的な関数の選択 例3


Slide 61

Slide 61 text

関数呼び出し時にデフォルト引数が使用されていない引数について
 "型がX₁~Xₙである関数F₁"および"Y₁~Yₙである関数F₂"を対象に
 ● Xₖ <: Yₖという制約を設定
 ○ A <: B:「AはBのサブタイプである」という意味 
 ○ 型XおよびYがbuilt-in integer types の場合は特別な制約が適用される 
 ○ 型パラメータに対する処理も別途あるが簡素化のため省略 
 ● 拡張関数については拡張対象(レシーバー)も引数として考え型制約に追加
 ● 宣言されている型制約を追加
 61 最も具体的な関数の選択 例3


Slide 62

Slide 62 text

F₁とF₂を入れ替えて構築される制約
 ● 󰢏 String <: String
 デフォルト引数は考慮しないので上記1つの制約だけとなる。
 ▶ 制約の検証結果:すべての制約を満たせる 
 62 最も具体的な関数の選択 例3


Slide 63

Slide 63 text

● F₁およびF₂について構築される制約は満たされている
 ● F₁とF₂を入れ替えて構築される制約は満たされている
 F₁およびF₂についてオーバーロード候補を1つに絞ることができない。
 型パラメータを持つかどうかでの判断でも絞り込み不可。
 この場合、デフォルト値が使われている引数の数をカウントする 。
 F₁は0個、F₂は1個であり、数が少ない方をより具体的であると判断する。
 したがって、F₁がF₂よりも具体的な関数であると判断できる。
 他にも可変長引数の数が少ない方を具体的であると判断するルールも
 存在する。
 63 最も具体的な関数の選択 例3


Slide 64

Slide 64 text

64 最も具体的な関数の選択 例3


Slide 65

Slide 65 text

65 型制約による最も具体的な関数の選択
 オーバーロード解決は型制約によって実現されている 
 型制約を構築、検証することで最も具体的な関数がわかる。
 オーバーロード解決 オーバーロード候補の 関数たちに関して型制約を構築 ▶ 引数の型を中心とした型制約 構築された型制約を検証 (必要に応じて追加手順を実施) 1 2

Slide 66

Slide 66 text

🐾 「へぇ〜」な仕様紹介 🐾
 66 難しい内容だけじゃなくて
 「そうなんだ」となる豆知識もたくさん


Slide 67

Slide 67 text

次のサンプルコードはエラーなく実行可能。
 余分な ?(nullability specifier)は無視される。
 (!!については仕様書内で言及がない)
 67 Nullable types
 コードが華やかになっていいね(?)

Slide 68

Slide 68 text

浮動小数点型(FloatおよびDouble)として比較するときと
 Any型として比較するときでは==演算子の挙動が異なる。
 浮動小数点型の場合はIEEE 754に準拠した比較が行われる。
 68 Value equality expressions


Slide 69

Slide 69 text

次のサンプルコードはエラーなく実行可能。
 KotlinではFTR(RT,A₁,...,Aₙ) → R ≡ FT(RT,A₁,...,Aₙ) → Rが
 成り立つ。
 つまり、レシーバ付き関数型は通常の関数型としても扱える。
 69 Function types


Slide 70

Slide 70 text

🐾 まとめ 🐾
 70

Slide 71

Slide 71 text

本日の振り返り
 71 ● Kotlin言語仕様書を紹介 ○ 詳細な仕様が記載されている ○ EBNFベースの表記法で文法を定義 ○ 数学的表現で仕様を説明 ● Kotlinの仕様をいくつか紹介 &解説 ○ 型システム & 組み込み型 ○ オーバーロード解決 ○ 「へぇ〜」な仕様たち

Slide 72

Slide 72 text

本発表を聞いて「こんなことできたんだ」「こういう挙動だったんだ」など
 新しい発見はあったでしょうか?
 みなさんの新しい発見に繋がっていれば幸いです。
 
 正直なところ言語仕様を知らなくてもコードは書けます。
 しかし、知っているとプラスに働く要素があることは確かです。
 なにより知識探求はおもしろいですよね。
 
 本発表をきっかけに、みなさんも言語仕様書を読んでみようと
 思ってもらえたならとても嬉しいです。
 きっとなにか得るものがあるはずです!
 72 終わりのあいさつ


Slide 73

Slide 73 text

🐾 Thank you 🐾
 73 ご清聴ありがとうございました!


Slide 74

Slide 74 text

🐾 補足資料 🐾
 74

Slide 75

Slide 75 text

Kotlinにおける関数はfirst-class functionであり、変数として扱ったり 
 他関数の引数として渡したりできる。 
 first-class functionを表現するためにKotlinでは関数型が用意されている。 
 関数型FTは以下の通り表現できる。 
 FT(A₁,...,Aₙ) → R
 ● Aᵢ:引数の型
 ● R:戻り値の型
 レシーバ付き関数型もある。 
 FTR(RT,A₁,...,Aₙ) → R
 ● RT:レシーバの型
 ● Aᵢ:引数の型
 ● R:戻り値の型
 75 関数型とは