ミュータビリティとイミュータビリティの狭間: 関数型言語使いから見たKotlinコレクション

2.7K Views

July 08, 24

スライド概要

Kotlin標準コレクションのイミュータビリティ(不変性)について、ScalaやClojureと比較しながら調べてみよう!

profile-image

「楽しく楽にcoolにsmartに」を理想とするprogrammer/philosopher/liberalist/realist。 好きな言語はClojure, Haskell, Python, English, français, русский。 読書、プログラミング、語学、法学、数学が大好き! イルカと海も大好き🐬

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

ミュータビリティと イミュータビリティの狭間 関数型言語使いから見たKotlinコレクション #kotlinfest2024_after_33 1

2.

🐬 lagénorhynque カマイルカ 株式会社スマートラウンドのプロダクトエンジニア 主要技術スタック: Kotlin + Ktor Kotlin Fest 2024のたまごスポンサー Server-Side Kotlin Meetupの運営企業 関数型言語/関数型プログラミングが好き 仕事や趣味でClojure, Scala, Haskellなどに長く 触れてきた 最近再入門したKotlinも好きになりつつある 🥚 😆 2

3.

1. きっかけ 2. 実験・調査 3. まとめ 3

4.

1. きっかけ 4

5.

🐬 Kotlin Fest 2024のセッションを聴いていた私 「Kotlinにはイミュータブルとミュータブルの2種 類のコレクションがあります」 「Kotlinを導入することで私たちはイミュータビリ ティを得ました」 Kotlinの List のコードとともに破壊的更新操作 ができない例が示される 5

6.

🐬の反応 Kotlinの List, Set, Map などは「イミュータブル」 (不変)なコレクションといえるのだろうか 同じくJVM言語(さらに関数型言語)のScalaや Clojureとはどう違うのだろう 確かKotlinには準標準ライブラリ(?)として kotlinx.collections.immutableがあったはず immutable/persistent collectionsを別途用意し 🤔 🤔 ているということは標準のコレクションはそうで はないと暗示しているような? 6

7.

2. 実験・調査 7

8.

Lisper/Clojurianの本能に従ってREPLで試してみる ℹ️ 実行環境 # Kotlin $ kotlinc -version info: kotlinc-jvm 2.0.0 (JRE 22.0.1) # Scala $ scala -version Scala code runner version 3.4.2 -- Copyright 2002-2024, LAMP/ EPFL # Clojure $ clj -version Clojure CLI version 1.11.3.1463 8

9.

Kotlinの List MutableList インスタンスを List 変数に代入する: >>> val xs: MutableList<Int> = mutableListOf(1, 2, 3) // イミュータブル(?)とされるList型の変数に代入できてしまった >>> val ys: List<Int> = xs >>> ys.add(4) error: unresolved reference: add ys.add(4) ^ >>> xs.add(4) res3: kotlin.Boolean = true >>> xs res4: kotlin.collections.MutableList<kotlin.Int> = [1, 2, 3, 4] // MutableList型の変数xsからの破壊的更新がysに必然的に波及している >>> ys res5: kotlin.collections.List<kotlin.Int> = [1, 2, 3, 4] 9

10.

>>> xs::class res6: kotlin.reflect.KClass<out kotlin.collections.MutableLi st<kotlin.Int>> = class java.util.ArrayList >>> ys::class res7: kotlin.reflect.KClass<out kotlin.collections.List<kotl in.Int>> = class java.util.ArrayList インターフェース kotlin.collections.MutableList は kotlin.collections.List を継承している ref. MutableList - Kotlin Programming Language 実体は java.util.ArrayList (Javaのミュータ ブルな可変長リスト) 10

11.
[beta]
List インスタンスをJavaのメソッドで操作する:
>>> val zs: List<Int> = listOf(1, 3, 2)
// Javaの破壊的なメソッドがコンパイル/実行時エラーなく呼び出せてしまった
>>> java.util.Collections.sort(zs, { a, b -> b.compareTo(a) }
)
// イミュータブル(?)とされるListのインスタンスが更新できてしまった
>>> zs
res10: kotlin.collections.List<kotlin.Int> = [3, 2, 1]

11

12.

>>> listOf<Int>()::class res11: kotlin.reflect.KClass<out kotlin.collections.List<kotl in.Int>> = class kotlin.collections.EmptyList >>> listOf(1)::class res12: kotlin.reflect.KClass<out kotlin.collections.List<kotl in.Int>> = class java.util.Collections$SingletonList >>> listOf(1, 2)::class res13: kotlin.reflect.KClass<out kotlin.collections.List<kotl in.Int>> = class java.util.Arrays$ArrayList >>> listOf(1, 2, 3)::class res14: kotlin.reflect.KClass<out kotlin.collections.List<kotl in.Int>> = class java.util.Arrays$ArrayList listOf に2要素以上を与えて得られる実体は java.util.Arrays.asList の戻り値と同じ(ミ ュータブルな固定長リスト) 12

13.

参考: Scalaの List ListBuffer インスタンスを List 変数に代入する: scala> val xs: List[Int] = List(1, 2, 3) val xs: List[Int] = List(1, 2, 3) // Listは独自のイミュータブルコレクション scala> xs.getClass val res0: Class[? <: List[Int]] = class scala.collection.immu table.$colon$colon // ミュータブルなListBufferとイミュータブルなListにまったく互換性なし scala> val ys: scala.collection.mutable.ListBuffer[Int] = xs -- [E007] Type Mismatch Error: -----------------------------// (エラー詳細は省略) ミュータブルコレクションとイミュータブルコレク ションの型階層が明確に分離されている 13

14.

List インスタンスをJavaのメソッドで操作する: scala> val zs: List[Int] = List(1, 3, 2) val zs: List[Int] = List(1, 3, 2) // ScalaのListはJavaのCollection/Listと互換性がない scala> java.util.Collections.sort(zs, Ordering[Int].reverse) -- [E007] Type Mismatch Error: -----------------------------// (エラー詳細は省略) // 内部的な実体を維持しながら(コピーせず) Javaコレクションに変換できる scala> import scala.jdk.CollectionConverters.* scala> val zs_ = zs.asJava val zs_: java.util.List[Int] = [1, 3, 2] // 破壊的更新操作はサポートしていない(実行時エラーになる) scala> java.util.Collections.sort(zs_, Ordering[Int].reverse) java.lang.UnsupportedOperationException 実体を維持したままJavaのインターフェースに適合 するように変換できるが、破壊的更新はできない (できたらイミュータブルコレクションと呼べない) 14

15.

参考: Clojureのvector (IPersistentVector) user=> (def xs [1 2 3]) #'user/xs ;; vectorは独自のイミュータブルコレクション user=> (class xs) clojure.lang.PersistentVector ;; IPersistentVectorインターフェースを実装している user=> (instance? clojure.lang.IPersistentVector xs) true ;; Java interopを円滑にするため、java.util.Listも実装している user=> (instance? java.util.List xs) true 標準ライブラリに独自のミュータブルコレクション はない 15

16.

vectorインスタンスをJavaのメソッドで操作する: user=> (def zs [1 3 2]) #'user/zs ;; 破壊的更新操作はサポートしていない(実行時エラーになる) user=> (java.util.Collections/sort zs >) Execution error (UnsupportedOperationException) at java.util. List/sort (List.java:514). Javaのインターフェースを実装しているが、破壊的 更新はできない(できたらイミュータブルコレクシ ョンと呼べない) 16

17.

3. まとめ 17

18.

イミュータブル(不変)っぽく見えてイミュータブル とは言いがたいデータ構造がある Kotlinの List はその例だといえる immutableではなく read-only (読み取り専用) なインターフェースと呼ぶのが正確と思われる ref. List - Kotlin Programming Language effectively immutable (実質的にイミュータブル) だと形容されることもあるが、抜け道が残れば当 然ながらイミュータビリティ(不変性)は保証され ないことになる 18

19.

🐬の感想: Kotlin言語/標準ライブラリの設計判断には実用 上の合理性を感じる ある意味でScala/Clojure以上にJava interopを 重視するからこそ必然性があるのかも(?) しかし、純粋な関数とデータで副作用を最小化/ 局所化するプログラミングスタイル(関数型プロ グラミング)を好む私としては、イミュータブル コレクションがデフォルトであってほしかった 😊 (Kotlinでの総合的な開発体験は好印象 ) 19

20.

Further Reading KotlinのListについて read-only vs immutable lists in Kotlin, Scala and Clojure: REPLでの簡単な実験結果のメモ by Kotlinのコレクションは「不変」と「可変」に分か れていない - kmizuの日記 Kotlin 紹介 - List / MutableList - PHONE APPLI Engineer blog 🐬 20

21.

Kotlin, Scala, Clojureのコレクションについて Collections overview | Kotlin Documentation Calling Java from Kotlin | Kotlin Documentation > Mapped types Mutable and Immutable Collections | Collections | Scala Documentation Conversions Between Java and Scala Collections | Collections | Scala Documentation Clojure - Data Structures > Collections 21

22.

関数型プログラミングについて JavaからScala、そしてClojureへ: 実務で活きる関 数型プログラミング | ドクセル: 関数型プログラミ ングの考え方と実利の紹介 by Clojureコレクションで探るimmutableで persistentな世界 | ドクセル: 不変かつ永続的なコ レクションの簡単な紹介 by Immutable object - Wikipedia Persistent data structure - Wikipedia 🐬 🐬 22