Daniel Pitts
12/17/2024, 5:39 PMimport com.stochastictinkr.json.*
fun main() {
val obj = jsonObject {
"name"("John Doe")
"age"(25)
"address" {
"number"(123)
"street"("Main Street")
"city"("Anytown")
"state"("AS")
"zip"(12345)
}
"phoneNumbers"[{
add("555-1234")
add("555-5678")
}]
"favoriteColor"(null)
"averageScore"(85.5)
}
println(JsonWriter.Pretty.writeToString(obj))
}
Resulting JSON:
{
"name": "John Doe",
"age": 25,
"address": {
"number": 123,
"street": "Main Street",
"city": "Anytown",
"state": "AS",
"zip": 12345
},
"phoneNumbers": [
"555-1234",
"555-5678"
],
"favoriteColor": null,
"averageScore": 85.5
}Edgar Avuzi
12/22/2024, 7:45 AM.let are redundant here (because there is no null to handle using ?.let ). Still this disadvantage does not outweight. IMOAhmed
01/17/2025, 10:04 AMarve
01/21/2025, 1:26 PMinterface Alphabet {
fun a(): String
fun b(): String
// and many more
fun z(): String
}
I thought I had a really bright idea, since the following is valid syntax:
class A : Alphabet by TODO("NOPE") {
override fun a() = "a"
}
I was hoping the delegation would act as with actual objects, routing calls to the override if they were present, and throwing NotImplementedError otherwise. Unfortunately, the TODO() is evaluated on instantiation of A() and not during method call 😞
// Hoping for
A().a() == "a" // true
A().b() // NotImplementedError
// but got
A() // NotImplementedError
Does anyone have an elegant way to partially implement an interface and default to NotImplementedError for the rest, without explicitly doing so for every single method?Mark
01/22/2025, 3:25 AMStateFlow from another StateFlow without requiring a CoroutineScope (so no new coroutine):
private class MappedStateFlow<T, R>(
private val original: StateFlow<T>,
private val transform: (T) -> R
) : StateFlow<R> {
override val replayCache: List<R>
get() = original.replayCache.map(transform)
override val value: R
get() = transform(original.value)
override suspend fun collect(collector: FlowCollector<R>): Nothing {
original.collect { collector.emit(transform(it)) }
}
}
fun <T, R> StateFlow<T>.mapState(transform: (T) -> R): StateFlow<R> {
return MappedStateFlow(this, transform)
}Eugen Martynov
02/10/2025, 8:11 AMcustomKeyListener?.onCustomKeyPressed()
something like
customKeyListener::onCustomKeyPressedRichard
03/05/2025, 7:27 AMenum class ToggleValue {
YES,
NO,
UNKNOWN
}
val ToggleValue.asBoolean: Boolean? // this one
get() = when (this) {
ToggleValue.YES -> true
ToggleValue.NO -> false
ToggleValue.UNKNOWN -> null
}
val Boolean?.asToggleValue: ToggleValue
get() = when (this) {
true -> ToggleValue.YES
false -> ToggleValue.NO
null -> ToggleValue.UNKNOWN
}Edgar Avuzi
03/07/2025, 1:47 AMMark
03/08/2025, 2:20 PMDensity as the receiver, but isn’t the API usage cleaner when doing this?
fun TextUnit.scale(scale: Float, density: Density): TextUnit {
if (this.isUnspecified) return this
return with(density) {
(scale * this@scale.toPx()).toSp()
}
}Ben Madore
03/11/2025, 1:31 AMval artifactName: Property<String> = project.objects.property(String::class.java)
that is consumed by maven-publish to set the name of the artifact (jar) to be published.
a couple of times, due to copy paste errors, folks have complained about failure to publish to artifactory when in fact they’ve just used the same artifactName in multiple modules of a project.
Does this approach make sense for identifying this case and proactively failing the build and alerting the user? Am i missing something much simpler?
// Add a plugin to detect duplicate artifact names
plugins.withId("maven-publish") {
// Create a simple task that will run on every project to check for duplicate artifact names
val checkDuplicateArtifactNames =
tasks.register("checkDuplicateArtifactNames") {
group = "verification"
description = "Checks for duplicate artifact names across all projects"
doLast {
// Map to store artifact names and their corresponding projects
val artifactMap = mutableMapOf<String, MutableList<String>>()
// Collect all artifact names from all projects
rootProject.allprojects.forEach { proj ->
val projExtension = proj.extensions.findByType(GDConventionsExtension::class.java)
if (projExtension != null && projExtension.artifactName.isPresent) {
val artifactName = projExtension.artifactName.get()
if (!artifactMap.containsKey(artifactName)) {
artifactMap[artifactName] = mutableListOf()
}
artifactMap[artifactName]?.add(proj.path)
}
}
// Find duplicates (artifact names used by more than one project)
val duplicates = artifactMap.filter { it.value.size > 1 }
// If duplicates are found, throw an error with details
if (duplicates.isNotEmpty()) {
val errorMessage = StringBuilder("\nDuplicate artifact names detected:\n")
duplicates.forEach { (artifactName, projects) ->
errorMessage.append("\n Artifact name '$artifactName' is used by multiple projects:\n")
projects.forEach { projectPath ->
errorMessage.append(" - $projectPath\n")
}
}
errorMessage.append("\nPlease ensure each module has a unique artifactName in its fooConventions block.\n")
errorMessage.append("For example:\n")
errorMessage.append("gdConventions {\n")
errorMessage.append(" artifactName.set(\"unique-name\")\n")
errorMessage.append("}\n")
throw GradleException(errorMessage.toString())
}
}
}
// Make sure the check runs as part of the build
tasks.named("build").configure {
dependsOn(checkDuplicateArtifactNames)
}
}czuckie
03/19/2025, 9:21 AMprivate fun String.asDomainSpecificObject(): DomainSpecificObject = ...
I would prefer a function to handle such things that explicitly took a string.
I thought the overwhelming view/opinion was that extension functions and properties were right when they extended the abstraction of the class that was being given an extension.
Beyond initial confusion and my own opinion, is there any reason to avoid such use of extension functions/properties, or should I embrace it?Vivek Modi
04/04/2025, 9:21 PMEmre
04/07/2025, 4:00 PMAlex Kuznetsov
04/11/2025, 5:51 PMLanguage annotation on a String literal for syntax highlighting and such, for example
@Language("SQL")
val sql = "SELECT weight, name FROM boxes"
But I'm reviewing code where parameters are annotated with it:
`fun doSomething(@Language("JSON") payload: String) { ...
why would we want to do that? what does it buy us?Sam Dukes
04/16/2025, 8:52 AMVivek Modi
05/01/2025, 8:35 PMJetpack Compose screen that fetches contact data using a ContactViewModel. The ViewModel uses StateFlow, performs API calls through a ContactsApi, and includes email validation logic using a UseCase. It all works, but I want to refactor this to align more with Kotlin best practices, Jetpack architecture guidelines, and better separation of concerns.czuckie
05/02/2025, 12:28 PMAlex Kuznetsov
05/06/2025, 12:44 PMrunCatching catches a Throwable not an Exception? Even official documentation states that
• The Error subclass represents serious fundamental problems that an application might not be able to recover from by itself. These are problems that you generally would not attempt to handle, such as OutOfMemoryError or StackOverflowError.
https://kotlinlang.org/docs/exceptions.html#exception-hierarchy
Personally we use a slightly modified version of runCatching that only catches an Exception. What am I missing?dany giguere
05/25/2025, 3:17 PMdany giguere
06/03/2025, 9:56 PMarve
06/06/2025, 10:17 AMinterface IExample {
fun <T> something(cls: KClass<T>)
}
inline fun <reified T> ITest.something() = something(T::class)
val t: IExample = Example()
// caller has to manually know about, and import extension function before they can do
t.something<String>()zt
06/07/2025, 5:54 PMval graph = FilterGraph {
// split input into 2 (default) outputs
filter("split") {
// get first output and assign to variable
val tmp = output {
filter("crop") {
option("out_w", "iw")
option("out_h", "ih/2")
option("x", 0)
option("y", 0)
}
// flip vertically
filter("vflip")
}
// get the second output
output {
// overlay tmp on top of this output
filter("overlay", tmp)
}
}
}czuckie
06/16/2025, 12:54 PMturbine for their coroutine testing?Zyle Moore
06/26/2025, 6:17 AMuseEffect(setTopLevel, props.pluginElementMarkers) {
val last = props.pluginElementMarkers.lastOrNull()
if (last == null) {
return@useEffect
}
val sequence = props.pluginElementMarkers.asSequence()
val topLevelList = mutableListOf<PluginElementMarker>()
var nextMarker = sequence.take(1).single()
while (nextMarker != last) {
val skip = nextMarker.skip
val size = when (nextMarker) {
is GroupElementMarker -> nextMarker.elementSize
is RecordElementMarker -> nextMarker.elementSize
is SubRecordElementMarker -> nextMarker.elementSize.toUInt()
}.toLong()
topLevelList += nextMarker
nextMarker = sequence
.dropWhile { marker -> marker.skip < skip + size }
.take(1)
.singleOrNull() ?: last
}
console.log("actually done")
setTopLevel(topLevelList)
}Paulo Cereda
06/27/2025, 3:42 PM.properties file correctly loads entries as UTF-8 — once the reader is using the correct charset, Properties works as expected. Consider this excerpt:
val expected = mapOf(
"italian" to "anatra",
"russian" to "утка",
"chinese" to "鸭子",
"japanese" to "アヒル",
"korean" to "오리",
"arabic" to "بطه",
"hindi" to "बत्तख",
...
)
I was wondering if I should hardcode these strings into the Kotlin file, specially that I have RTL ones in there. Is this okay or there is a better way? Any suggestions are welcome! Thanks!arve
06/30/2025, 7:52 AMimport kotlinx.serialization.StringFormat
import kotlinx.serialization.json.Json
private val format: StringFormat = Json { encodeDefaults = true }
object MyFormat : StringFormat by format
When I try to inline format the expression insists on referring to the class Json instead of the factory function Json
Any tips to avoid the intermediate format variable?arve
09/30/2025, 10:58 AMjava.time.Instant over kotlinx.datetime. We are leveraging the typealias trick to make Instant @Serializable.
This has been working just fine up until now, but today i was writing a specific test and came over something surprising:
When using the aliased type inside a @Serializable data class, it works as expected. But when trying to serialize a naked MyInstant i get an exception 🤯
typealias MyInstant = @Serializable(InstantSerializer::class) java.time.Instant
@Serializable
data class Test(val i: MyInstant)
fun main() {
val epoch = MyInstant.EPOCH
println(Json.encodeToString(Test(epoch))) // {"i":"1970-01-01T00:00:00Z"}
println(Json.encodeToString(epoch)) // kotlinx.serialization.SerializationException: Serializer for class 'Instant' is not found.
}arve
09/30/2025, 10:59 AMAli Khaleqi Yekta
10/24/2025, 9:51 PMimport kotlin.concurrent.Volatile
object RandomPool {
private val writeLock = ReentrantLock()
private val random = kotlin.random.Random.Default
@Volatile private var array = FloatArray(0)
private var _array = array
operator fun get(index: Int): Float {
// Available in the thread-local cached array
val local = _array
if (index < local.size) {
return local[index]
}
// Available in general
val latest = array
if (index < latest.size) {
_array = latest
return latest[index]
}
// Not available, need to grow
ensureCapacity(index + 1)
return array[index]
}
fun ensureCapacity(capacity: Int) =
writeLock.withLock {
// Double-Checked Locking: After acquiring the lock, check the condition again.
// Another thread might have already grown the array while this thread was waiting.
val currentArray = array
if (capacity <= currentArray.size) return@withLock
// This thread has the lock and has confirmed the array is still too small.
// Proceed with the resizing operation.
val oldSize = currentArray.size
// Grow the array with some extra capacity to reduce the frequency of re-allocations.
val newSize = maxOf(capacity, (1.5 * oldSize).toInt())
// Copy-on-Write: Create and populate the new array completely before publishing it.
val newArray = currentArray.copyOf(newSize)
for (i in oldSize until newSize) {
newArray[i] = random.nextFloat()
}
array = newArray
_array = newArray
}
}
I believe in this case, the _array should be an acceptable optimization and shouldn't cause any wrong output being returned, but asking AI, it keeps on insisting otherwise, and points out that there actually is a way that _array can return `0.0`(not randomly, but as an uninitialized value). The array is only ever set to completely filled arrays, and the _array is only updated afterwards, plus the values themselves never change. So, I don't seem to see any problem. Do you know if it's actually wrong, or the AI is hallucinating?MiguelDecimal128
11/17/2025, 11:15 PM