tokuhirom's Blog

pure kotlin な double array の実装である KDary をリリースした

https://central.sonatype.com/artifact/io.github.tokuhirom.kdary/kdary https://github.com/tokuhirom/kdary

KMP(Kotlin Multiplatform) 環境で Mac アプリを実装していた。その中で雑な文書要約をしたくなり、 TF-IDF を使いたくなった。日本語で TF-IDF を使うには単語を分かち書きする必要があるわけだが、分かち書きするには形態素解析機を使うのが手っ取り早いということになる。しかしながら、KMP 環境では利用できる日本語形態素解析機は存在していない。 ないものは作るしかないので、作るのだが、日本語の形態素解析を効率よくやるためには共通接頭辞検索を行う必要がある。このために使えるライブラリも KMP 環境には存在していない。 そこで、まずは共通接頭辞検索のためのライブラリを、他の言語から移植することとした。

MeCab の実装を参考にすれば、移植元は Darts,Darts-Clone, MARISA あたりがパッと思い浮かぶ。tx,rx, ux とかでも良い。xcdatcrawdad でも良い。

LOUDS でもダブル配列でもいいんだけど、シングルファイルで実装されてて移植が簡単そうな darts-clone をベースとすることとした。Darts よりも darts-clone のほうが生成ファイルが小さくなるという点も魅力である。そこそこの速度がでて、実績あるやつならまじでなんでもよかった。

darts-clone の移植は、chatgpt などの力も借りてやろうと思ったが、思ったよりうまくいかず。c++ のコードでは、メソッド呼び出し時に参照やポインタを渡す事ができ、そこを書き換えることが可能だが、そういう概念を chatgpt がうまく解釈できないようだ。今どき、c/c++ 以外でそういう言語ないしな。。 というわけでほとんど手書きした。テストケースは概ね chatgpt に生成させ、darts-clone の出力と突合し、正解データを darts-clone のものに揃えるように実装を調整しながらデバッグしていった。 本来、darts-clone では配列の添字の範囲が size_t だが、kotlin では配列の添字の範囲が Int なので、Int の範囲になるように調整した。

2024-07-06 に実装開始して、2024-07-16 に maven central にリリースしているので、片手間にやって約10日の実装期間ということになる。

工夫したところ

はまったところ

ByteArray を Set に入れようとしてハマった。

val setByteArray =
    setOf(
        "a".toByteArray(),
        "a".toByteArray(),
        "b".toByteArray(),
    )
println(setByteArray)

のような場合、"a".toByteArray() が重複登録されてしまう。 まぁ、これは JVM から始まった言語だからしょうがないが、罠い。

Maven Central へのリリース

KMP のライブラリは Maven Central へのリリースが可能だ。 先日の kotlin fest で発表していた atsushieno さんのブログ記事を参考にして試したところうまくいった。昔は Maven Central への登録は担当者との温かみのある JIRA 上でのやりとりが必要となっていて、めんどくさかったが、今は github 認証をすれば、io.github.tokuhirom 以下にスッとアップロードできるようになっていて、圧倒的に簡単になっている。

https://zenn.dev/atsushieno/articles/d066e757c9640f https://speakerdeck.com/atsushieno/building-kotlin-multiplatform-libraries-in-2024-cc23c2ab-bbbd-4e28-bd05-c46985685a23

atsushieno さんに感謝。

libs.kmp.icerock.dev への登録

https://libs.kmp.icerock.dev に KMP なライブラリはまとまってるんで、ここに登録していく。

Pull request を出せばいいだけなので簡単だ。 https://github.com/icerockdev/libs.kmp.icerock.dev/pull/111

まとめ

Kotlin fest 2024 に参加してきたョ

Kotlin fest 2024 に参加してきたんで、そのレポート。 JJUG CCC 2024 Spring から一週間たたずの開催。

https://www.kotlinfest.dev/kotlin-fest-2024

2024年版 Kotlin サーバーサイドプログラミング実践開発

https://speakerdeck.com/n_takehata/kotlin-server-side-programming-practice-2024 https://fortee.jp/kotlin-fest-2024/proposal/9c5d8033-173a-4785-a072-abe61af9a531

竹端 尚人さんの発表。

2021年に発売された Kotlin サーバーサイドプログラミング実践開発 からの状況の変化をおさらいしよう、という内容。

書籍は spring-boot, junit,mybatis みたいな構成だったのを、ktor, Koin, kotest, JOOQ にしたらいいんじゃね、みたいな話。

ほかはともかくとして、mybatis/JOOQ の関係性は3年前と一緒な気がするなァ、とは思いつつ。あと、個人的には SQLDelight とかも気になる。

個人的には、Ktor が DI を実装するということをすでに発表しているので、DI 周りはその動向を注視する必要がありそうというのが気になる。ktor の DI の出来がよかったら、そっちにみんな流れる気がしている。 なので、今 spring boot 使ってる案件とかは、ktor DI が出てから検討した方がよい気がする。いつ出るのか知らんけど。。 https://blog.jetbrains.com/kotlin/2024/03/ktor-2024-roadmap-di-update/

結構、ktor の DI がリリースされると、新規案件では boot よりも ktor を採用するケース増える可能性あるんじゃないかなぁ。どうなるかわからないけれど。

あと、kotest は個人的にはそんなにはまってないです。

この手のテクニカルスタックを選ぶときに、JVM 以外でも動くかということはそろそろ気にしたほうがいい気はしていて、FaaS などで Kotlin/JS, Kotlin/Native を採用するケースも今後出てくると思うので、そうなったときにその環境でも使えるものを選んだ方が楽なんじゃないかなぁという気がしております。

Okioに愛を込めて

https://fortee.jp/kotlin-fest-2024/proposal/b6a4b643-825d-4068-bb58-c659feeb8fbd

RyuNen344 さんの発表。最近、kotlin native 使ってるのもあり、Okio は最近触ってたのでタイムリーな話題。kotlinx.io が公式みがあるものの、Okio にあって kotlinx.io にないものがめちゃくちゃ多いんで、現実的には kotlin native 使う場合は Okio 一択ぽさありますね。

2024年に公開するに相応しいKotlin Multiplatformライブラリを構築する

https://speakerdeck.com/atsushieno/building-kotlin-multiplatform-libraries-in-2024-cc23c2ab-bbbd-4e28-bd05-c46985685a23f

Atsushi Eno さんの発表。 kotlin multiplatform 用のライブラリを公開するこつ、みたいなセッション。

網羅的に説明されていて良かった。個人的には、maven central は難しすぎるので、何か別のレポジトリを JetBrains がホスティングする未来をお願いしたいところです。

kotlin multiplatform 用のライブラリって今めちゃくちゃ貧弱なので、ライブラリ作ったら案外使われると思うので、チャンスだと思う。Java のライブラリって作っても使われにくいけど、kotlin だと結構いけそうな気がする。

もっとKotlinを好きになる!K2時代のKotlin Compiler Plugin開発

https://x.com/kitakkun_pb/status/1804444762491302176

kitakkun さんの発表。K2 コンパイラのフェーズを細かく日本語で解説してて良かったです。 なんかネタがあったら Compiler Plugin 作ってみたいが、、少なくとも Perl の B tree よりはドキュメント多くていじりやすそうだった。

K2のKotlin IDEプラグインの中を覗いてみよう♪

https://fortee.jp/kotlin-fest-2024/proposal/ff006096-bfbe-4389-8e76-ef2a528a4477 https://speakerdeck.com/yanex/k2nokotlin-idepuraguinnozhong-wosi-itemiyou

Yan Zhulanow さんのセッション。

Kotlin は、IDE と密に連携しながらコンパイラ開発してるっていう話とかもありつつ。 Phase とか整理して並列化されるようになったということで、IDE の安定性も上がるっぽく、楽しみ。

JetBrains のエンジニアは強いマシンスペックのマシンで開発していたが、K2 にしたらメモリ少なくても IDE の開発が可能になったので、メモリ2GBチャレンジが流行った、っていう話がいい話だった。

IDEA の K2 サポート、とはいえまだまだ kotlin native だと挙動不審だったりするので今後に期待。 「IDE のこのエラーは、こういう理由でおきててー」みたいな解説があって面白かった。

Analysis API が公開されるというアナウンスもあり、楽しみ。Compiler Plugin は正直、ネタがパッと思いつかないのだが、、Analysis API は結構興味あり。

その他: Kotlinらしいコードを書こう - Convert Java File to Kotlin File のあとにやること

Kotlin Fest の内容についてですが、 https://y-anz-m.blogspot.com/2024/06/kotlin-convert-java-file-to-kotlin-file.html Kotlinらしいコードを書こう - Convert Java File to Kotlin File のあとにやること というセッション(登壇者体調不良で飛んだセッション)は、kotlin 初心者には良さそうでした。 最近、Kotlin いきなり書くことになってる人とかにおすすめです(普段から書いてる人には当たり前の話が多そう)。

kotlin-wrappers の 1.0.0-pre.757 から 1.0.0-pre.758 での不具合を報告して修正済みになった話

kotlin-wrappers の 1.0.0-pre.757 から 1.0.0-pre.758 までのバージョンで、もんだいがあった..

println(process.platform)

というコンパイルが以下のようなエラーでコンパイル出来なくなったのだ。

> Task :compileProductionExecutableKotlinJs FAILED
e: java.lang.IllegalStateException: IrTypeParameterPublicSymbolImpl for [ node.stream/StreamOptions.Companion.invoke|invoke(web.abort.AbortSignal?;kotlin.Double?;kotlin.Boolean?;kotlin.Function2<kotlin.Throwable?,kotlin.Function1<kotlin.Throwable?,kotlin.Unit>,kotlin.Unit>;kotlin.Boolean?;kotlin.Function1<kotlin.Function1<kotlin.Throwable?,kotlin.Unit>,kotlin.Unit>;kotlin.Boolean?){0§<node.stream.Stream>}[0] <- Local[<TP>,0|TYPE_PARAMETER name:T index:0 variance: superTypes:[node.stream.Stream] reified:false] ] is already bound: TYPE_PARAMETER name:T index:0 variance: superTypes:[node.stream.Stream] reified:false
        at org.jetbrains.kotlin.ir.symbols.impl.IrBindablePublicSymbolBase.bind(IrPublicSymbolBase.kt:69)
        at org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl.<init>(IrTypeParameterImpl.kt:48)
        at org.jetbrains.kotlin.ir.declarations.impl.AbstractIrFactoryImpl.createTypeParameter(IrFactoryImpl.kt:380)
        at org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC.createTypeParameter(IrFactoryImplForJsIC.kt:361)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeIrTypeParameter$lambda$8(IrDeclarationDeserializer.kt:286)
        at org.jetbrains.kotlin.ir.util.SymbolTable.declareScopedTypeParameter(SymbolTable.kt:421)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeIrTypeParameter(IrDeclarationDeserializer.kt:308)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeIrTypeParameter$default(IrDeclarationDeserializer.kt:279)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeTypeParameters(IrDeclarationDeserializer.kt:465)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.access$deserializeTypeParameters(IrDeclarationDeserializer.kt:68)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeIrFunction$ir_serialization_common(IrDeclarationDeserializer.kt:1204)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeDeclaration(IrDeclarationDeserializer.kt:821)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeDeclaration$default(IrDeclarationDeserializer.kt:815)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeIrClass(IrDeclarationDeserializer.kt:390)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeDeclaration(IrDeclarationDeserializer.kt:820)
        at org.jetbrains.kotlin.backend.common.serialization.IrDeclarationDeserializer.deserializeDeclaration$default(IrDeclarationDeserializer.kt:815)
        at org.jetbrains.kotlin.backend.common.serialization.IrFileDeserializer.deserializeDeclaration(IrFileDeserializer.kt:40)
        at org.jetbrains.kotlin.backend.common.serialization.FileDeserializationState.deserializeAllFileReachableTopLevel(IrFileDeserializer.kt:127)

https://github.com/JetBrains/kotlin-wrappers/commit/9efe9b6a1aceefb8b86114b02667660cb4009e35 でワークアラウンドがコミットされた。この変更がコミットされた 1.0.0-pre.759 がリリース済み。が、なんかまだ maven repository で見えない。

本質的にはコンパイラのバグなので、YouTrack に登録されている。すでに修正済みなので、次回のリリースで直るだろう。 https://youtrack.jetbrains.com/issue/KT-68943/JsPlainObject-breaks-when-interface-has-type-parameters

JJUG CCC 2024 Spring 参加レポート

はじめに

2024年の春、昨日開催されたJJUG CCC 2024 Spring に参加してきました!家庭の事情で午後からの参加となりましたが、Javaコミュニティの熱気を肌で感じながら、最新技術の情報や多くの開発者との交流を楽しむことができました。この記事では、キーノート、ブースでの会話、懇親会、そしてアンカンファレンスの様子をレポートします。

キーノートセッション

Java First. Java Always.

最初のキーノートは、「Java First. Java Always.」というタイトルで、OracleのJavaエキスパートたちが登壇しました。Javaの最新機能を紹介しながら、次世代アプリケーション開発の未来を描く内容でした。特に、オンプレミスからクラウドまで対応するJavaの強みが強調されており、開発者として非常に励みになりました。

FFMでJITコンパイラを作ってみた

次に聞いたのは、「FFMでJITコンパイラを作ってみた」というセッション。Java 22で正式に導入されたForeign Function & Memory API(FFM)を使って、JITコンパイラを実現するという興味深い内容でした。ffmasmライブラリを使って、Javaからネイティブコードを動的に生成・呼び出す方法が紹介され、FFMの新たな可能性を感じました。

ブース訪問

イベント中にFindy、Samuraism、Azulのブースを訪れ、それぞれの担当者とお話をしました。

懇親会

懇親会にも参加しました。LT大会が非常に盛り上がっており、参加者同士の活発な交流が見られました。変に食事があるよりも、乾き物しかない開場の方がかえって懇親しやすいと感じました。皆がリラックスして会話を楽しめる雰囲気がとても良かったです。

アンカンファレンス

アンカンファレンスにも参加しました。今回はフレームワークの話とAIの話が中心でした。

フレームワークの話

Spring Boot 3系への移行が大きなトピックでした。Jakarta EEへの移行が主な変更点であるため、実際のアップデート内容はそこまで大きくないとの意見も。QuarkusやMicroProfileも選択肢として挙がり、開発者たちの関心の高さが伺えました。

AIの話

AIを用いたコーディングについて話し合いました。特にGitHub Copilotのデモが盛り上がり、ほとんどの参加者が実際に使用していることが印象的でした。寺田さんが別のイベントの動画を流しながら、GitHub Copilotのデモについて詳しく解説してくれました。今後の進歩に大きな期待が寄せられています。

まとめ

JJUG CCC 2024 Springは、Javaコミュニティの最新情報や技術トレンドを学ぶ絶好の機会でした。キーノートやブースでの交流、懇親会、そしてアンカンファレンスを通じて、多くの刺激を受けました。これからもJavaの進化と共に、開発者として成長していきたいと思います。


参加者の皆さん、そして運営スタッフの皆さん、お疲れ様でした。また次回のイベントでお会いしましょう!

ScreenCaptureKit で display 全体をキャプチャするときの話

ScreenCaptureKit では display 全体をキャプチャするときに、initWithDisplay:excludingWindows: で excludingWindows に empty list を渡したらなぜか動かない。initWithDisplay:includingApplications:exceptingWindows: に動いている全部のアプリケーションをリストアップしたら動く。

https://federicoterzi.com/blog/screencapturekit-failing-to-capture-the-entire-display/

ドキュメントとかみてもよくわからんけど、事実そう。

kotlin native のデバッグ用の gradle task を定義する

こんな感じ。stdin も渡した方がいいね

// ./gradlew :capjoy:runDebug -PexecArgs="displays"
tasks.register<Exec>("runDebug") {
    dependsOn("linkDebugExecutableNative")
    val arguments = project.findProperty("execArgs")?.toString()?.split(" ") ?: listOf()
    args(arguments)
    environment("CAPJOY_GRADLE_RUN_DEBUG", "true")
    executable = file("$buildDir/bin/native/debugExecutable/capjoy.kexe").absolutePath
    standardInput = System.`in`
}

Kotlin でゲーム作るなら korge が良さそう

https://korge.org/

普通に使えそうな感じがする。

kotlin native を動かしてみる

最初にkotlin native を動かした場合

e: org.jetbrains.kotlin.konan.MissingXcodeException: An error occurred during an xcrun execution. Make sure that Xcode and its command line tools are properly installed.
Failed command: /usr/bin/xcrun xcodebuild -version
Try running this command in Terminal and fix the errors by making Xcode (and its command line tools) configuration correct.

というようなエラーになることがあります。

sudo xcode-select --switch /Applications/Xcode.app

この場合はこうすればOK.

build.gradle.kts を以下のようにする。

plugins {
    kotlin("multiplatform") version "2.0.0"
}

group = "org.example"
version = "1.0-SNAPSHOT"

kotlin {
    macosArm64("native") {
        binaries {
            executable()
        }
    }

    sourceSets {

    }
}

repositories {
    mavenCentral()
}

ソースファイルを src/nativeMain/kotlin/Main.kt あたりに置いておけばOK。

Hello, world レベルのビルドが、6秒ぐらい。 コマンドの実行自体は速い。

tauri v2 では SystemTray は TrayIcon という名前に変わっている。

https://v2.tauri.app/start/migrate/from-tauri-1/#migrate-to-tray-icon-module

v2 だと SystemTray は TrayIcon に変わっている。 マイグレーションガイドの通りにやれば、動きそう。

僕が neojot で tauri v2 beta を使い始めた頃には、ドキュメントが皆無だったが、最近は migration guide が充実しているので良い。

kotlin-power-assert-demo

kotlin 公式で power-assert が出てた。これは最高っぽい。 (まだできたてホヤホヤ Experimental です)

実際動かしてみて、その結果をレポジトリに置いておいた。 https://github.com/tokuhirom/kotlin-power-assert-demo

assertj/assertK などのアサーションライブラリは便利なのだのだけど、、

そこで、power-assert ですよ。

assertK でこう書いてたコードが

    val people = listOf(Person(name = "Sue"), Person(name = "Bob"))
    assertThat(people)
        .extracting(Person::name)
        .containsExactly("Sue", "Bob")

こう書いたら

    @Test
    fun testComplex() {
        val people = listOf(Person("Sue"), Person("Bob"))
        assert(people.map { it.name } == listOf("Susie", "Bob"))
    }

こうだ!

    Assertion failed
    assert(people.map { it.name } == listOf("Susie", "Bob"))
           |      |               |  |
           |      |               |  [Susie, Bob]
           |      |               false
           |      [Sue, Bob]
           [Person(name=Sue), Person(name=Bob)]

最高!

なお、multiplatform にも対応しているみたい。 とくに、kotlin/js とかでテスト書く時にはコレ使うと便利そうねぇ。 (kotlinx.test は便利だがマッチャの種類が少なめ。そこをこれでカバーできそう。 )

tauri アプリにアイコンを設定する方法

https://tauri.app/v1/guides/features/icons/

これで解決。簡単。

npm run tauri icon ~/Documents/neojot.png

kotlinx.serialization のこと

kotlinx.serialization は、kotlin 用のシリアライゼーションライブラリである。 gradle のプラグインが提供されていて、@Serializable アノテーションがついているクラスに対するシリアライザを生成してくれる。 プラグインのソースコードは https://github.com/JetBrains/kotlin/tree/master/plugins/kotlinx-serialization にある。なにかコード生成ライブラリ使ってるのかと思ったら kotlin そのものの機能を使ってそう。

kotlinx.serialization のドキュメントは以下の場所にある。Polymorphism のような機能があって Jackson に出来ることは一通りできそう。 https://github.com/Kotlin/kotlinx.serialization/blob/4bf4113c2c6936e841caf2a8670382e701e7fcc2/docs/serialization-guide.md

たとえば以下のように使うのだが、、

package org.example

import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

@Serializable
data class Greeting(val greeting: String)

fun main() {
    println("Hello World!")
    println(Json.encodeToString(Greeting("Hello, Kotlin/JS!")))
}

生成されるコードは以下のようになっている。Greeting$serializer.serialize が生成されてるので、実行時には高速に処理ができそうだ。 (kotlin のデコンパイルを IDEA がサポートしてほしいなぁと思いつつ幾星霜)

// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available

package org.example

@kotlinx.serialization.Serializable public final data class Greeting public constructor(greeting: kotlin.String) {
    public companion object {
        public final fun serializer(): kotlinx.serialization.KSerializer<org.example.Greeting> { /* compiled code */ }
    }

    internal constructor(seen0: kotlin.Int, greeting: kotlin.String?, serializationConstructorMarker: kotlinx.serialization.internal.SerializationConstructorMarker?) { /* compiled code */ }

    public final val greeting: kotlin.String /* compiled code */

    public final operator fun component1(): kotlin.String { /* compiled code */ }

    public open operator fun equals(other: kotlin.Any?): kotlin.Boolean { /* compiled code */ }

    public open fun hashCode(): kotlin.Int { /* compiled code */ }

    public open fun toString(): kotlin.String { /* compiled code */ }

    @kotlin.jvm.JvmStatic internal final fun `write$Self`(self: org.example.Greeting, output: kotlinx.serialization.encoding.CompositeEncoder, serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit { /* compiled code */ }

    @kotlin.Deprecated public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<org.example.Greeting> {
        public final val descriptor: kotlinx.serialization.descriptors.SerialDescriptor /* compiled code */

        public final fun childSerializers(): kotlin.Array<kotlinx.serialization.KSerializer<*>> { /* compiled code */ }

        public final fun deserialize(decoder: kotlinx.serialization.encoding.Decoder): org.example.Greeting { /* compiled code */ }

        public final fun serialize(encoder: kotlinx.serialization.encoding.Encoder, value: org.example.Greeting): kotlin.Unit { /* compiled code */ }
    }
}

さて、実際速度的にはどうなのかな? というのが気になりますよね。 kotlinx.serialization のレポジトリ、ちゃんとベンチマークコードが入っているのに、結果をのせてないところが奥ゆかしいですね。 https://github.com/Kotlin/kotlinx.serialization/blob/4bf4113c2c6936e841caf2a8670382e701e7fcc2/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/JacksonComparisonBenchmark.kt

./gradlew jmh

とかすれば、結果が得られるので、手元で動かして結果を見てみると良さそう。

Benchmark                                               Mode  Cnt      Score      Error   Units
JacksonComparisonBenchmark.jacksonFromString           thrpt   10    731.704 ±   17.971  ops/ms
JacksonComparisonBenchmark.jacksonSmallToString        thrpt   10   9779.674 ± 3045.866  ops/ms
JacksonComparisonBenchmark.jacksonToString             thrpt   10   1811.471 ±   55.360  ops/ms
JacksonComparisonBenchmark.jacksonToStringWithEscapes  thrpt   10   1508.877 ±  122.538  ops/ms
JacksonComparisonBenchmark.kotlinFromStream            thrpt   10   1080.475 ±   82.937  ops/ms
JacksonComparisonBenchmark.kotlinFromString            thrpt   10   1375.436 ±   89.197  ops/ms
JacksonComparisonBenchmark.kotlinSmallToOkio           thrpt   10   8141.993 ±  111.842  ops/ms
JacksonComparisonBenchmark.kotlinSmallToStream         thrpt   10  10325.260 ± 2784.316  ops/ms
JacksonComparisonBenchmark.kotlinSmallToString         thrpt   10  10832.368 ±  306.662  ops/ms
JacksonComparisonBenchmark.kotlinToOkio                thrpt   10    898.711 ±   26.997  ops/ms
JacksonComparisonBenchmark.kotlinToStream              thrpt   10   1011.233 ±   62.126  ops/ms
JacksonComparisonBenchmark.kotlinToString              thrpt   10   1912.123 ±  192.133  ops/ms
JacksonComparisonBenchmark.kotlinToStringWithEscapes   thrpt   10   1336.079 ±  303.871  ops/ms

結果はこんな感じになる。 chatgpt で markdown に整形した結果が以下。そんなにすごい差があるわけでもない。

Kotlin/JS のサンプルコード集をつくりました

https://tokuhirom.github.io/kotlin-js-samples/

Kotlin/JS 面白いなぁとおもって試してみた。 ので、サンプルコード集を作ってみました。git clone するとすぐに試せます。

なかなかの力作なのでお試しあれ。

見た目と kotlin/js

Kotlin/JS と CSS framework とか MUI のような UI library などについて考える。

kotlin/js を使うときのフレームワークは基本、どうするんだ。

kotlinx.rpc 使ってみたよ

kotlinx.rpc が楽しそうなので触ってみたのでメモ。

https://github.com/Kotlin/kotlinx-rpc/tree/main/samples/ktor-web-app ここにあるサンプルがわかりやすくてすぐ動くので、これを触って

path とかゴチャゴチャ悩まずに kotlin の interface だけ定義すれば良いのは楽かも。 とはいえ、websocket ベースだとログとか悩まないといけないという面もあり、難しいところ。

gRPC サポートはいって安定したら、サーバー間通信に使うと良いかも。

kotlin/js のチュートリアルに関するメモ

https://github.com/kotlin-hands-on/web-app-react-kotlin-js-gradle/issues/42

kotlin hands on の web-app-react-kotlin-js-gradle のコードを実行してみていて、、kotlin-wrappers の最新版に差し替えて動かしてみたら全く動かなかったんで、これ動くようにしてくれないかねえ、と言ってみた。今日現在は web-app-react-kotlin-js-gradle は kotlin-wrappers の 1.0.0-pre-430 を使っている。

kotlin-wrappers の pre-750 版だと document.getElementById("root") の結果が org.w3c.dom.Element なのに対して、createRoot の引数は web.dom.Element となっていて、、この2つは相互に変換することは出来なさそう。

どうしたらいいの?

ということで、issues で聞いてみた。

import web.dom.document instead of import kotlinx.browser.document で解決。

gradle の dependency locking っていつから使えるの?

https://docs.gradle.org/4.8/release-notes.html 4.8から使えるっぽい。歴史がすごい。

The endpoint を組み立てた

最近は keyball44 を利用しているわけだが、親指周りにキーがもっと多かったら便利なのかなぁと思い、YMGWorks さんの The endpoint を booth で購入し、試してみた。

トラックボールの位置は左手親指。トラックボールの位置の自由度が高いのは良いなぁ。一方で、ビルドガイドで「こうだったらこう。そうじゃなかったらこう」みたいな記述が多いので、注意して読まないといけないので集中力を要する。

左手親指においたらトラックボールの位置が結構遠くて、僕の手だとちょっとキツかった。 また、キーが多いとはいえ、多かったら多かったで、使うキーの種類をもっと増やしたいとはならないなぁ、と感じたので、keyball44 でちょうど良いのかも。と思った。

また、The endpoint のトラックボールモジュールは蓋がついていないため、傾けてるとすぐに外れて転がっていってしまうのがちょっと不便。トラックボールモジュールの追加部品をけぺおさんが作っているので、そういったものを使わないと、なかなか使いにくいかもしれず。

トラックボールモジュールに含まれているネジの種類が多くて、ネジの判別をするのが結構難しいので、マステの上に置いて数えながらやると良さそう。

ロータリーエンコーダーっていうのを初めて取り付けてみたが、自分的には用途がちょっと思い浮かばなかった。

などなど。

Keyball44 に横スクロール用のボタンを設置すると便利

https://github.com/tokuhirom/keyball/commit/8ae41b881609df2692aa4daa899131a171976202

こんなパッチをファームウェアに当てた。 完全に自分用なので雑。

Special Key Code の 16 を押下している間だけ、スクロールモードに入ると同時に HORIZONTAL スクロールロックをかけるという感じ。 これにより、めっちゃ快適に横スクロールできるようになって最高。

まじおすすめです。

Discussions にも投稿してみた。 https://github.com/Yowkees/keyball/discussions/561

reactor-netty の Connection prematurely closed BEFORE response

https://projectreactor.io/docs/netty/release/reference/index.html#faq.connection-closed

公式ドキュメントにトラブルシューティングの方法がまとまっている。