Kotlin E07:库升级后旧消费者还能运行吗
Java 调用 Kotlin 时默认参数去哪了 已经验证,默认参数并不会自动让 Java 省略实参;`@JvmOverloads` 才会另生成 Java 能直接调用的重载。库作者一旦放出这个重载,问题就从“现在能否编译”变成“旧调用方带着已有 class 文件升级库之后,还能否链接并保持结果不变”。同样的函数声明,在源码、JVM 符号和业务返回值三个层面有不同的兼容结果。 固定消费者,只替换库 隔离工程 examples/kotlin-language/abi-compat/ 使用 Kotlin/JVM 2.2.21、JDK 21 和 Gradle 8.14,通过 maven-publish 将三个示例版本发布到专用 /tmp Maven 仓库。1.0.0 的库对外提供: 12345object TaskLabels { @JvmStatic @JvmOverloads fun render(id: String, suffix: String = "!"): String = id + suffix} Java 旧消费者...
Kotlin E06:挂起事务究竟等到哪里
换个 Dispatcher,阻塞还在吗 区分挂起与占用线程,事务中途挂起,连接归谁 用同步 JDBC 检查连接所有权。换到 Spring 后,最容易误读的是普通方法拦截器的返回:它看见了 `proceed()` 的返回值,并不等于挂起调用者已经获得业务结果,更不等于事务已经提交。仓库另有 [深入 Spring E06](/2026/10/02/深入-Spring-E06-Kotlin挂起调用事务与上下文边界/) 使用另一套版本和独立实验;本篇只复验 Kotlin 累计工程的边界。 拦截器比调用者先返回 SpringCoroutineTransactionTest 用两个 CompletableDeferred 充当闸门。被代理的 suspend read() 先报告进入,再等待放行。普通 MethodInterceptor 调用 invocation.proceed() 后立即把计数加一;测试在放行之前检查计数已经是 1,而异步调用 caller.isCompleted 仍为 false,放行后 caller.await() 才得到 done。JUnit XML 原始输出: 1S...
Go E05:Web 框架只替换哪一层
E04通过 gRPC 适配原服务。本篇仍在同一个任务服务里做另一项局部替换:给 HTTP 应用端口换路由适配器,不复制任务提交、SQL 领取或 worker。选定 Go 1.27.1 和 github.com/go-chi/chi/v5 v5.3.2,具体依赖及 chi 源码 SHA 随完整实验包交付;另有SHA-256和独立复跑方法。 路由框架不替业务提交状态 taskstats serve 新增 --http-adapter stdlib|chi,缺省仍为原标准库 ServeMux。chi 路由器把 POST /tasks 交给原 taskHTTPService.create,GET /tasks/{id} 与 POST /tasks/{id}/cancel 只把框架取到的 ID 填回 PathValue 再交给原 lookup/cancelTask。因此 JSON/字段限制、队列容量、SQL 写入与终态仲裁还是前 39 章那一份服务。--http-adapter unknown 在监听前退出 2;单独的管理 listener 不随 HTTP 适配器一起放出诊断路由。 把两个...
Kotlin E05:虚拟线程和协程怎样比较同一等待任务
24 将 `suspend` 与实际线程区分开;37 用 JMH 测局部成本。JDK 21 又提供虚拟线程,能在一个看起来同步的调用里执行大量等待。如果只报“创建了多少协程 / 虚拟线程”,没有统一任务和限额,两种计数不能推出服务吞吐,更不能推出取消和资源管理是同一种契约。 这次比较收窄到 320 个合成编号任务,每项等待 8ms,最多允许 32 个任务进入等待段。虚拟线程使用 Executors.newVirtualThreadPerTaskExecutor()、Java Semaphore 和 Thread.sleep;协程使用 async(Dispatchers.Default)、协程 Semaphore.withPermit 和 delay。宿主为四 CPU 的 Linux、Ubuntu OpenJDK 21.0.12.1、Kotlin/coroutines 2.2.21/1.10.2,工具链版本与原始逐轮输出在 writing-plans/kotlin/verification/E05/。都是受控等待,不访问 HTTP、数据库或真实客户端。 先对齐“做了多少事” 每个路...
Kotlin E04:JS 与 Wasm 导出的是同一个接口吗
E02 的 `commonMain` 状态机先在 JVM 与 Node 的 JS 目标上运行;E03 增加 linuxX64 ELF。现在把同一个 `TaskState` 编到 Kotlin/Wasm,是否就能让 JavaScript 客户端不经适配地调用同一组导出?公共业务源码可以一样,生成模块的加载方式、异常对象与异步契约却不自动相同。 本轮固定 Kotlin Multiplatform 2.2.21、Gradle 8.14、JDK 21,在 Node 22.23.2 上直接载入实际生成的 JS 与 Wasm 文件。Wasm 概述在核对时仍注明 Beta;没有浏览器、DOM、WASI 或服务器流量的结果。详细版本、失败构建、四目标 XML 和 Node 客户端断言在 writing-plans/kotlin/verification/E04/。 状态规则共享,导出声明分开放 原 commonMain 的 advanceTask 仍没有 kotlin.js 或 Wasm 导入。构建另外声明 wasmJs { nodejs() },各自的测试目标复用 comm...
Go E04:RPC 与流式调用怎样映射任务期限
E03把受控本地函数接在原服务分析器上。本篇沿用同一个累计任务服务的 HTTP/SQL 状态机,通过真正的 TCP gRPC 提交任务并流式看状态。核心不是给 202 换一种序列化格式,而是把 RPC 调用期限、服务端退出和任务终态分开。完整包、SHA-256、独立复跑随文交付。 先冻住传输约定 固定 Go 1.27.1,gRPC-Go google.golang.org/grpc v1.67.1,protobuf 间接依赖 v1.34.2;go.mod/go.sum 和实际 go list -m all 保留版本闭包。本篇使用 gRPC-Go 的 ServiceDesc 和强制 JSON codec,线协议是 application/grpc+json,并未提供 .proto 或生成跨语言 protobuf 客户端。这能实测同版本 Go 客户端与服务端的 RPC/stream 生命周期,但不能宣称默认 gRPC protobuf 客户端可互通。连接只走 loopback insecure.NewCredentials(),TLS、认证及远程网络为 NOT_RUN。 rpc_ta...
Kotlin E03:Native 跨过 C 指针边界要付出什么
E02 把任务状态放进 `commonMain`,但只在 JVM 和 Node.js 上运行过测试。为多平台 Gradle 配置增加 `linuxX64()` 后,同一份状态转移还必须编译成 Native 可执行文件并运行,才能知道这一目标在当前机器上确实可用。至于接入 C 库,`commonMain` 的 sealed 分支不会自动告诉 C 如何接收字符串、谁持有字节数组地址、什么时候能释放它。 这里以本地合成输入验证 Linux x86_64。Kotlin/Native 编译器、Gradle 插件均固定为 2.2.21,使用原 Wrapper 8.14、JDK 21 和宿主 GCC 13.3.0。没有 macOS、Xcode 或 Swift 编译器;Swift/Objective-C 的运行结果标 NOT_RUN,不能凭 Linux C 绑定推出 Apple 目标已验收。 公共规则先要由 Native 自己跑一次 shared-model 沿用 E02 的 commonMain/TaskState.kt,新增 linuxX64 目标。相同的 commonTest 在这个目标下...
Kotlin E02:任务状态能共享到哪里
12 里定义的 `Queued → Running → Succeeded` 没有 JVM 线程、数据库连接,也不需要 Android 界面。39 则把同一套状态接到 Netty、PostgreSQL 和进程退出上。如果要让另一种运行环境复用任务规则,到底该移动哪一段代码?把整个 JVM 工程标成“跨平台”不仅编不过,还会掩盖最关键的问题:业务状态和执行这些状态的基础设施,有不同的可移植边界。 本篇从正在使用的 :domain 模块抽出状态模型,在 JVM 和 Node.js 上各跑一次相同的断言。实验并不涉及 Android、Native、浏览器或多端服务发布;“两端通过”的范围就是这两个运行目标。 先把真正纯粹的规则移出来 原来的 TaskState.kt 有两个不同职责。前半段定义状态、信号和转移;末尾的 acceptSubmission(store, id, text) 依赖 TaskStore,而 store 的具体实现位于 JVM 域模块。移动前半段到独立 Gradle 工程 shared-model/src/commonMain/kotlin/example/tas...
Go E03:cgo 与 unsafe 怎样改变资源边界
E02让任务提交校验不再依赖运行时逐字段检查。本系列的业务仍由原 Go HTTP/SQL 服务处理;本篇只给原分析器接一个受控的本地函数,检查文字输入能否穿过 C 边界。完整工程及实验包、SHA-256、独立复跑步骤随文提供。 先规定谁拥有内存 固定 Go 1.27.1 的 cmd/cgo 文档区分 Go 内存指针与 C 内存指针:Go 指针传给 C 要遵循 pin 规则,C.CBytes 在 C 堆新建数据副本,需要调用者释放。native/sum.go:SumASCII 先拒绝零长度、超过 4096 字节、NUL 或非 ASCII 的输入,再用 C.CBytes 复制字节到 C 内存;只在 task_ascii_sum 调用期间把这份 C 内存通过 unsafe.Pointer 转成 C 字节指针,返回前以 defer C.free 释放。C 函数只在给定长度内求字节和,不保存地址,也不访问网络或数据库。 这条路径没有把 Go slice 的地址留给 C,但使用了 unsafe 和本地编译器,原 Go 类型系统无法替 C 函数证明越界、悬垂或其他内存安全性质。本地函数没有异步...
Go E02:反射与代码生成如何校验任务字段
E01确认了接口、值与取消的局部契约。这次只动同一个任务服务提交入口的字段校验:请求的 Text 不能为空白,配置中的 MaxWords 必须为正。生成校验承担实际 HTTP 路径,反射版本只作对照,业务领取、SQL 与状态转移不复制第二套。完整包、摘要和复跑步骤附在同名目录。 错误在哪一刻出现 字段声明在 taskvalidation/schema.go:Fields:Text string 带 check:"nonblank",MaxWords int 带 check:"positive"。cmd/generate-taskvalidation 用固定 Go 1.27.1 的 go/parser 读取 AST,先核验字段名、类型与标签,再用 go/format 生成 taskvalidation/generated.go:Validate。原 http_tasks.go:create 仍先作 JSON/体积校验,之后调用生成函数;拒绝空白正文仍返回原有 400 和原有错误文本,原 SQL 插入只发生在校验通过之后。 反例把 Text 的...










