
r/scala

Use of uninitialized val doesn't result in a compiler failure
​
object test:
val y = x
val x = 5
Will compiles but test.y will = 0. I want it to fail to compile is there a way to do that? -Wsafe-init sounds like it should but doesn't.
Create stunning TUI interfaces with jatatui (previously tui-scala)
Apologies for the java interface, but i needed it outside of the scala bubble. Still eminently usable from scala, and still native image-safe.
There are three layers to this:
- crossterm. Manually written facade for the rust library. has been thoroughly tested over the years it has backed `tui-scala`
- jatatui. Mostly ported 1-1 by claude, given very specific porting instructions. 2k tests and a bunch of runnable demos means most of it works. API should be stable. Whatever porting quirks remain are likely easily fixed.
- jatatui-react . POC-level code to express yourself using familiar react concepts. Has been used to implement one complex TUI app, but will likely see extensive changes going forward
🚀 Play Framework's newest Premium Sponsor: Evertrust
📢 We’re excited to welcome Evertrust as our newest premium sponsor! 🎉
evertrust.io is a leading European software provider specialized in integrated PKI and digital certificate lifecycle management solutions, helping companies:
- gain visibility over their TLS and machine identities,
- avoid costly outages caused by expired certificates, and
- automate certificate renewal and deployment across complex, hybrid environments.
We’re proud to partner with a cybersecurity player so focused on digital trust and sovereignty in Europe.
Welcome on board, Evertrust!🔐
Open-sourcing ShipReq – a requirements platform written in FP Scala/Scala.js
gist.github.comdatomlite - A zero-dep, Datomic-style "DB-as-a-value" you can drop into your Scala 3 apps (JVM, JS, Native)... (Looking for feedback!)
Hello! Been tinkering on datomlite for a while. Its about ready for trials ... and would love your sharp eyes on (1) how the typed datalog-style API feels? (2) If there are some glaring macro faux-pas?..
li-nk : a Scala backed social platform. develop your interests, find your community
Hi everyone , I just launched the Early Access release of li-nk , a community focused social platform surrounding human interests.
Through the development process I've tried to contribute back to the Scala tooling that li-nk has employed; as well as to other open source projects.
I've contributed upstream to ProtoQuill (both upstream and where I maintain a a maven repository), Caliban, zio-telemetry, and Scala Metals.
The platform geography is unfortunately currently limited to the USA. However I am looking forward to the possibility of internationalizing soon as well.
Regarding Scala. I've been working on and off with Scala since 2014 and have met some of you at Scala Up North (2019?) / Scala Days 2023 / Scala related activities in the Seattle metro.
I hope that you might consider trying out the li-nk platform. Thanks for your consideration and support for our favorite programming language !!
https://www.linkedin.com/posts/li-nk-social-network_li-nk-activity-7461429061517496320-Zhi2
Job opportunity Scala Dev India .
Guys ,anyone looking for job in scala in India ,let me know . My company is hiring ,I can refer . Also I was laid off few months ago ,but got another scala role . So someone interested kindly let me know . Min exp 2 year .
built a small http4s app that indexes youtube transcripts into postgres and the whole thing is about 350 lines of scala
i work at a fintech company and we have about 170 youtube videos. internal engineering talks, recorded architecture reviews, vendor integration walkthroughs, a bunch of conference talks people bookmarked over the years. all sitting in a shared playlist that nobody scrolls through because the titles are useless. someone would ask in slack "didn't we do a talk about event sourcing last year" and nobody could find it.
i built a small app to make them searchable. http4s server with a single endpoint that takes a query string and returns matching videos with transcript snippets. postgres backend with full text search. a simple html frontend with one search box because i didn't want to deal with a separate frontend project.
for pulling the transcripts i use transcript api:
npx skills add ZeroPointRepo/youtube-skills --skill youtube-full
the ingestion side is a cli tool built with decline. give it a youtube url or a file of urls and it pulls each transcript through the api, parses it, and inserts it into postgres using doobie. i wrote a TranscriptRepo algebra with an insert and a search method. the search uses postgres tsvector with a GIN index and ts_headline for the snippet extraction.
the http4s routes are one file. GET /search with a query param, returns json or html depending on the accept header. i used circe for the json encoding. the html response is just a scalatags template inlined in the route because i didn't want to set up a template engine for one page.
the part that felt nice was how well doobie handles the postgres full text search queries. the tsvector and tsquery types map cleanly and i wrote a custom fragment for the ts_headline call. no raw string interpolation, just composed fragments. it reads well.
deployed it on our internal k8s cluster as a docker container. the docker image is built with sbt-native-packager. the whole app starts in about 2 seconds which is fine for an internal tool.
about 170 videos indexed. the engineering team uses it before design reviews to check whether someone already gave a talk on the approach they're considering. someone from product started using it to find specific things our CTO said in recorded all-hands which i didn't anticipate.
the codebase is a TranscriptRepo trait, a SearchService class, the http4s routes, the decline cli, and a Main object. maybe 350 lines total. no cats-effect streaming or fs2 for this one, just straightforward IO with doobie transactions.
I built an open-source, high-concurrency state machine for AI tokens using Scala 3, Pekko, and GraalVM
Hey r/scala,
I recently, I noticed AI startups hitting massive race-condition problems when trying to track API token usage natively in Postgres.
I decided to build a standalone, open-source quota firewall to solve this, and I wanted to push the JVM to its limits.
The architecture:
- Written in Scala 3.
- Core engine uses Apache Pekko (Typed/Cluster). The wallet state lives entirely in-memory on a single Actor, making double-spending mathematically impossible without any row-level database locking.
- Event Sourced via Pekko Persistence R2DB, JDBC (Postgres) for the immutable audit log.
- I set it up to compile to a standalone GraalVM native image for instant startup and tiny memory footprints.
It was an awesome challenge figuring out how to handle "Zombie Holds" (when an LLM API times out and freezes a user's tokens) using Pekko's TimerScheduler.
I'd love for some experienced Scala devs to tear apart the architecture or give me feedback on the GraalVM/Pekko setup.
Repo is here: https://github.com/baseledger-io/baseledger
Kyo going pure Scala 3 - 1.0.0-RC2 is out!
v1.0.0-RC2
v1.0.0-RC2 is a large release. Nine new modules land, the HTTP stack is rewritten from scratch in pure Scala (with both client and server running on JVM, JS, and Native), and Scala Native picks up the remaining pieces it needed to be a viable target for everything Kyo ships 🚀
A recurring theme across the release is dependency reduction. Netty, libcurl, h2o, JCTools, Caffeine, HdrHistogram, the Java OpenTelemetry SDK, sttp, and tapir are all gone, replaced by pure-Scala implementations that share Kyo's scheduler and effect channels and compile to all three platforms. The new modules build directly on that foundation: durable workflows (kyo-flow), container orchestration (kyo-pod), feature flags (kyo-config), and OpenTelemetry export (kyo-stats-otlp) all rely almost exclusively on pure Scala implementations compiled to JVM, JS, and Native.
New Features
New modules
kyo-http(README) replaces the sttp and tapir integrations with a single client+server API that compiles to all three platforms, dropping Netty for a pure-Scala transport that handles TLS, WebSocket, Unix sockets, SSE, and NDJSON. Routes are an interpretable pure data structure with type-level field tracking viaRecord. (by @fwbrasil in #1479, #1518)kyo-pod(README) is a Docker and Podman client that talks the Docker Engine API directly over the Unix socket, with a shell execution fallback. Logs, stats, exec output, and image pulls stream from the first byte. Predefined containers for Postgres, MySQL, and MongoDB are provided for convenience. (by @fwbrasil in #1524)kyo-flow(README) is a durable workflow engine. AFlowis a plan, not an execution: every step is checkpointed before the next begins, and if the process crashes another executor claims the work via a time-limited lease and replays from the last checkpoint, skipping completed steps. Workflows suspend on declared inputs and resume when signals arrive through the engine API or the auto-generated HTTP endpoint, so human approval, async events, and other external triggers are first-class. Saga-style compensation, per-step retry and timeout, and an event audit trail are all built in. (by @fwbrasil in #1498)kyo-schema(README) is a single-source-of-truth schema module. DeriveSchema[A]from a case class and get JSON, Protobuf, type-safe lenses, structural diffs that ship and replay, batched mutations, incremental builders, and bidirectional conversions between structurally compatible types. No annotations, no boilerplate. The module depends only onkyo-dataand has no dependency on Kyo's effect runtime, so it can be adopted as a standalone library. (by @fwbrasil in #1517)kyo-parsemoves theParseeffect out ofkyo-preludeand parameterizes it on input type, so token-stream parsers compose with lexers. The internals are reworked to add error accumulation and AST recovery, which makes the effect suitable for real-world parsers like programming languages and LSPs. (by @Iltotore in #1305, #1404, #1421, @fwbrasil in #1400)kyo-config(README) provides typed feature flags and structured configuration.StaticFlagresolves once at class load for infrastructure settings;DynamicFlagevaluates per call for feature gates and A/B tests. Both support a rollout DSL with path matching, percentage weights, and deterministic bucketing, with automatic topology detection for K8s, AWS, and GCP. (by @fwbrasil in #1511)kyo-stats-otlpreplaces the JVM-onlykyo-stats-otelwith a from-scratch pure-Scala OTLP/HTTP exporter built onkyo-http. Speaks the protocol directly, runs on JVM, JS, and Native, and disables itself whenOTEL_EXPORTER_OTLP_ENDPOINTis unset. (by @fwbrasil in #1491)kyo-logging-jplandkyo-logging-slf4jare platform logging bridges extracted fromkyo-core.kyo-coreno longer pulls SLF4J as a dependency; pick whichever bridge matches your stack. (by @hygt in #1396)
Cross-platform process management
Path, Command, and Process now work consistently across JVM, JS, and Native, with safer APIs that drop java.* types in favor of Stream where it makes sense. The System effect also gains availableProcessors and architecture, classifying os.arch tokens consistently across platforms. (by @fwbrasil in #1505, #1522, #1532)
New primitives
Dictis a new low-allocation immutable map with a dual internal representation: a flatSpanfor up to 8 entries (linear scan, no hashing) and aHashMapabove that. Iteration takes separate key and value parameters to avoid boxing in hot paths. Used internally by the newRecordencoding. (by @fwbrasil in #1470, #1523)GatereplacesBarrierwith a primitive that covers both the cyclic-barrier and phaser use cases. Parties pass through together once everyone arrives, with multi-pass coordination and pass tracking; aGate.Dynamicvariant supports runtime join and leave plus hierarchical subgroups. (by @fwbrasil in #1480)Exchangeis a new low-level primitive for ID-multiplexed protocols like HTTP/2 and WebSocket subprotocols, where requests are tagged with an ID and responses are routed back by that ID. It encapsulates the pending-promise map, the reader fiber, the cleanup races, and backpressure for unsolicited events. Intended for protocol clients, not application code. (by @fwbrasil in #1501)New
Recordencoding: records no longer allow duplicate field names with different types. The old encoding stored a runtimeTagto disambiguate, which the new invariant plusConversion-based subtyping replaces, also reducing memory footprint. (by @fwbrasil in #1467, #1472)Base64: pure-Scala RFC 4648 implementation that cross-compiles to all three platforms without depending on
java.util.Base64. (by @fwbrasil in #1531)
Interop and convenience APIs
Kyo
Streamand ZIOZStreaminterop: bidirectional conversion between the two. (by @HollandDM in #1461)Abort.ignoreandAbort.loopUntil: two new error-handling combinators. (by @fwbrasil in #1507)
Improvements
Native parity
Scala Native catches up to JVM and JS on the modules where it used to be missing or partial. Full HTTP client and server support lands (by @fwbrasil in #1479), along with a JCTools queue port that replaces unoptimized stubs (by @fwbrasil in #1489), a Cache primitive that retires the JVM-only Caffeine dependency (by @fwbrasil in #1487), Prometheus and OTel-inspired histograms in kyo-stats that replace HdrHistogram (by @fwbrasil in #1483), signal handling so Native binaries respond to SIGINT and SIGTERM (by @hearnadam in #1408), and a scheduler jitter fix that addresses a Native-specific Thread.sleep contention (by @fwbrasil in #1485). reactive-streams now cross-compiles to JS and Native (by @fwbrasil in #1484), and the ZIO interop modules are enabled for Native (by @fwbrasil in #1482).
General
Scoped
Fiber.init: fibers used to be fire-and-forget by default, easy to lose track of.Fiber.initnow introduces aScopepending effect and registers a finalizer that interrupts the fiber when the scope closes.Fiber.initUnscopedpreserves the prior behavior. (by @johnhungerford in #1379)Reliable blocking detection and thread-interrupt propagation: the scheduler's stalled-worker detector now reads per-thread CPU time instead of thread state, which several kernel-level blocking operations leave at
RUNNABLEdespite genuinely being blocked. Fiber interrupts also reach into truly blocking I/O likeServerSocket.acceptnow: the JVM thread interrupt is dispatched, gated to fire only when the worker is genuinely parked so it can't damage in-flight work. (by @fwbrasil in #1510)Nested
.nowand.laterindirect:.nowand.laterinside another.now, and.laterinside another.later, now compile, removing a common ergonomic wart. (by @ahoy-jon in #1369)ConcreteTagderivation for unions and intersections: generic methods overAbort[E | Closed]compile with justConcreteTag[E]instead of requiringConcreteTag[E | Closed]at every call site. (by @johnhungerford in #1397, @fwbrasil in #1512)Smaller items:
Isolate.restorebecomes contravariant and gains anisolate.nesthelper (by @fwbrasil in #1388);AsyncShiftis specialized forListandSetso direct-styleforlowers to the optimizedkyo.Kyo.*calls (by @ahoy-jon in #1302);Aspect.initaccepts dynamic tags viaTag.dynamic(by @fwbrasil in #1389);Safepoint.ensureno longer re-registers the same finalizer on each loop iteration (by @hearnadam in #1434).
Concurrency and streams
Streamparallel map memory leak:mapParand friends let an unbounded number of follower fibers accumulate when transformations took long. The rewrite caps concurrency via aMeterand a bounded queue. (by @johnhungerford in #1378)Queue.closeAwaitEmptydrain on every call: only the first caller used to wait for the queue to drain; subsequent callers returnedfalseimmediately. They now join the same wait. (by @hearnadam in #1430)
Data and observability
Span gains the common Scala-collection-style APIs that don't box. Tag's string representation is now deterministic, which matters when tag strings are used as persistence keys. KyoException.getMessage no longer silently drops the wrapped exception's class and text in production mode, so "Unexpected error for X" now carries the actual cause. STM is optimized and the opacity bug from a missing second transaction timestamp is fixed. (by @fwbrasil in #1401, #1495, #1523, #1455, #1456, #1459)
Tooling and ecosystem
Scala 3.8.x support across the matrix (3.8.1 and 3.8.3), with scheduler-related modules also compiled on Scala 3.3.7 (LTS). (by @fwbrasil in #1451, @road21 in #1508, @hearnadam in #1407)
Caliban migrated to
kyo-http: the GraphQL integration now runs on the unified transport. (by @fwbrasil in #1490)Docs:
AGENTS.mdand an expandedCONTRIBUTING.md, plus a copy-to-code button on samples and a new N Queens example usingChoice. (by @fwbrasil in #1468, @hearnadam in #1384, @Yummy-Yums in #1402, #1399)
Fixes
kyo-stats-registrynever exported metrics:StatsRefresh'sThreadFactorybuilt threads without passing theRunnable, sorefresh()never ran, breaking metrics (this export is now replaced bykyo-stats-otel). (by @Salim-belkhir in #1457)Channel, Stream, and Async correctness:
Channel.closeAwaitEmptyno longer drops the last element on streaming consumers (the slow-pathdrainUpToshort-circuited the for-comprehension when the take had transitioned the channel); multi-producer split-batches are correct;Stream.mapParpropagatesClosed;Async.foreachis rewritten to fix a per-item index bug and to use work-stealing instead of static batching. (by @fwbrasil in #1464, #1503, #1497, #1514)Interrupt and scope races: a best-effort workaround reduces the race where a parent interrupted before joining its child failed to propagate the interrupt (the fix handles a pending
Async.Joinduring interrupt rather than relying solely on the link that hadn't been registered yet); first wave ofScopecorrectness fixes also lands. (by @fwbrasil in #1458, #1504)zio-testassertTrueover scope-managed resources:TestResult.resultwas a lazy val evaluated afterScope.runclosed finalizers, so assertions over scoped resources observed torn-down state. Fixed by forcing the arrow chain inside the test body. (by @gcsolaroli in #1529)Type machinery:
Tagvariance is now read fromtypeArgsrather thansymbol.declarations,Nullis no longer considered a subtype of literal types, andTypeMap/Env.getwith intersection types is now a compile error. (by @fwbrasil in #1449, #1447, @ahoy-jon in #1492)Data and miscellaneous:
Chunk.toArraycorrectly unboxes for primitives (by @fwbrasil in #1448);Text#dropUntilNextoff-by-one (by @toonvanacker in #1383);Layer.using(by @ahoy-jon in #1423);Frame.internalcleanup for clearer stack traces (by @hearnadam in #1365); test additions and stability forNestedHandler,closeAwaitEmpty, andSemaphore(by @ahoy-jon in #1493, @steinybot in #1375, @hearnadam in #1433); README code-block fence and Retry section heading (by @kyusu in #1437, @markehammons in #1533).
Breaking changes
Fiber.initis now scoped; useFiber.initUnscopedfor the prior behavior. (by @johnhungerford in #1379)Barrierremoved, replaced byGate. (by @fwbrasil in #1480)Sync.Unsafe.applyrenamed toSync.Unsafe.defer. (by @fwbrasil in #1466)Abort[Throwable]removed fromFutureconversion result types; failures still surface as panic. (by @fwbrasil in #1465)Rowremoved; use the newRecordencoding. (by @fwbrasil in #1471)Recordno longer allows duplicate field names with different types. (by @fwbrasil in #1472)Parsemoved tokyo-parseand parameterized on input type. (by @Iltotore in #1305, @fwbrasil in #1400)kyo-sttpandkyo-tapirremoved; migration guide inkyo-http/README.md. (by @fwbrasil in #1537)kyo-stats-otelremoved; usekyo-stats-otlp. (by @fwbrasil in #1491)- SLF4J no longer a dependency of
kyo-core; pickkyo-logging-slf4jorkyo-logging-jpl. (by @hygt in #1396) TypeMap/Env.getwith intersection types is now a compile error. (by @ahoy-jon in #1492)
New Contributors
- @toonvanacker made their first contribution in #1383
- @Yummy-Yums made their first contribution in #1399
- @Iltotore made their first contribution in #1305
- @hygt made their first contribution in #1396
- @kyusu made their first contribution in #1437
- @Salim-belkhir made their first contribution in #1457
- @markehammons made their first contribution in #1533
- @gcsolaroli made their first contribution in #1529
Full Changelog: https://github.com/getkyo/kyo/compare/v1.0-RC1...v1.0.0-RC2
Join us at the Scala Hangout tomorrow evening (May 14th)!
The Scala Hangout will be having its May hangout tomorrow (May 14th) evening. There have been some interesting articles published this last month, but conversation is open as always.
Hi r/scala — disclosure up front: I the maintainer of Aegis-KMS, an
open-source key manager we just shipped v0.1.1 of. This post is *not*
about the product, it's about the language/stack choice. The product
choice is in a different post next week.
Most "we picked Scala for X" posts age badly because they're aesthetic
arguments. The four properties we actually needed from the language
were:
- Total case analysis on every security decision (sealed traits +
-Wunused, so a forgotten principal kind doesn't compile) - Composable invariants without inheritance — the same KeyService
algebra is wrapped by Authorizing, Auditing, ActorBacked
decorators, each adding one orthogonal concern. - Single-writer state with deterministic event-sourced replay
(Pekko Typed actor + journal — the actor IS the user guardian,
no Promise/Await dance). - A clean fallback when the type system runs out (Cats Effect 3).
The full write-up with code from the actual repo is here:
Where the stack cost us:
- Pekko version pinning hell — Tapir transitively pulls a different
pekko-stream and ManifestInfo refused to start; we had to
dependencyOverride across all artifacts.
- sbt-dynver vs. Pekko user-guardian — the original
Promise/Await pattern hung on cold start on JDK 21 + sbt's
classloader. The fix was making the ActorSystem itself the actor
(`ActorSystem[T] <: ActorRef[T]` in Pekko Typed).
- Scala 3 + Doobie 1.0.x had codec quirks we worked around.
GitHub: https://github.com/sharma-bhaskar/aegis-kms
v0.1.1 has 160 tests, scalafmt + scalafix clean, library tier
explicitly Pekko-free for embeddability.
Happy to take pushback in comments — especially from anyone who
considered Scala for a similar control-plane shape and went a
different way.