https://kotlinlang.org logo
Join SlackCommunities
Powered by
# codereview
  • e

    Elena van Engelen

    10/30/2024, 1:17 PM
    For me 2 sounds overengineered. Would go for 1 with also scope function Like
    Copy code
    suspend fun createFoo(foo: Foo) {
        // Create record in DB and then perform additional tasks within scoped functions
        dbService.saveFoo(foo)
            .also {
                // Cache invalidation
                cacheService.invalidateCacheForFoo(foo.id)
            }
            .also {
                // Update search engine
                searchEngineService.addFooToSearch(foo)
            }
    }
    d
    • 2
    • 2
  • d

    dave08

    10/30/2024, 4:48 PM
    Could this be improved? https://kotlinlang.slack.com/archives/C5UPMM0A0/p1730305874378839?thread_ts=1730291447.478059&cid=C5UPMM0A0
    • 1
    • 1
  • a

    azabost

    10/31/2024, 2:47 PM
    Is this initialization of overriden val still OK?
    Copy code
    interface Foo {
        val xyz: String
    }
    
    class Bar : Foo {
        
        override val xyz: String
        
        init {
            xyz = compXyz("XYZ")
        }
        
        fun compXyz(key: String) = key.reversed()
    }
    
    fun main() {
        val s = Bar()
        println(s.xyz)
    }
    I'm asking because I seem to get this warning in Android Studio (I use Kotlin 1.9.24 in the project):
    Property must be initialized, be final, or be abstract. This warning will become an error in future releases.
    and not sure how to interpret this issue: https://youtrack.jetbrains.com/issue/KT-57553/Implement-deprecation-for-open-val-with-backing-field-and-deferred-initialization-in-K1 i.e. whether this is going to be deprecated soon or not I don't see any issues running it in Kotlin Playground though (tried both 1.9 and 2.0) šŸ¤”
    j
    c
    • 3
    • 15
  • m

    MatyÔŔ Vítek

    11/10/2024, 4:00 PM
    https://kotlinlang.slack.com/archives/C0B8MA7FA/p1731254297620149
    j
    d
    +2
    • 5
    • 13
  • d

    Daniel Pitts

    11/10/2024, 6:17 PM
    I've started working on a library to help JSON creation. It has 2 parts: 1. Json building DSL (which I'm calling
    kson
    for now). (Example code here) 2. Type safe Json wrapper with JsonSchema generation and validation. (Example code here). This feature was heavily inspired by Exposed DAO. I will add examples of the DSLs in 🧵 too. Please let me know any thoughts or suggestions.
    c
    • 2
    • 11
  • c

    christophsturm

    11/18/2024, 11:36 AM
    what is a good way to share code between catch blocks? here is the code with the duplicated code:
    Copy code
    val TOTAL_TRIES = 3
                val triedPorts = ArrayList<Int>(TOTAL_TRIES)
                while (true) {
                    val realPort = port ?: findFreePort()
                    triedPorts.add(realPort)
                    val undertow: Undertow = buildUndertow(rootHandlers, defaultHandler, realPort, host)
                    try {
                        undertow.start()
                    } catch (e: RuntimeException) {
                        // it seems that undertow sometimes wraps the bind exception in a runtime exception
                        if (e.cause is BindException) {
                            if (port != null)
                                throw RestaurantException("could not start server on port $port")
                            if (triedPorts.size == TOTAL_TRIES)
                                throw RestaurantException("could not start restaurant after trying $TOTAL_TRIES times." +
                                        " ports tried: $triedPorts")
                            continue
                        }
                    } catch (e: BindException) {
                        // if no port was specified, we retry
                        if (port != null)
                            throw RestaurantException("could not start server on port $port")
                        if (triedPorts.size == TOTAL_TRIES)
                            throw RestaurantException("could not start restaurant after trying $TOTAL_TRIES times." +
                                    " ports tried: $triedPorts")
                        continue
                    }
    all strategies that i tried just made it more confusing imo.
    k
    j
    • 3
    • 3
  • a

    arve

    11/26/2024, 1:30 PM
    I have two helper functions that take either a
    List<T:Any?>
    or a
    T:Any?
    , with slightly different implementations. The goal is for the caller not to have to care whether the param is a value or collection of values (SQL interpolation stuff) What’s a good way to allow these to have the same name? currently I have
    Copy code
    inline fun <reified T : Any> Statement.helperList(param: Collection<T>?, stmt: (Param<*>) -> Statement) = TODO("thing that has to know T")
    inline fun <reified T : Any> Statement.helper(param: T?, stmt: (Params<*>) -> Statement) = TODO("Same thing but handled a differnt way since its not a collection"
    Currently if I give them the same name,
    helper
    will be called even if the argument is a collection, because it also matches
    Any
    . Is there a way to constrain T so that it’s ā€œNot collectionā€ somehow?
    j
    d
    r
    • 4
    • 11
  • e

    Ellen Spertus

    12/01/2024, 3:03 AM
    Copy code
    // version 1
    println(comment.body)
    println()
    
    // version 2
    println("${comment.body}\n")
    
    // version 3
    println(comment.body + "\n")
    1ļøāƒ£ 5
    2ļøāƒ£ 1
    e
    • 2
    • 1
  • g

    Gouri Panda

    12/01/2024, 11:23 PM
    Hi everyone! šŸ‘‹ I’m excited (and a little nervous!) to share that I’m testing my very first app, WordFlipster, and I need your help to make it better! šŸ™Œ WordFlipster is a fun word game where you reverse words to solve puzzles—it’s simple, challenging, and great for all ages! 🧩 Since I’m new to app development and still learning as I go, your feedback would mean the world to me. Here’s how you can help: 1. Opt-in to the closed test via this link: [https://groups.google.com/g/google-group-closed-testing-2] or [https://forms.gle/1TRSvwqavVzLiFmHA]. 2. Try out the game and explore the features. 3. Share your honest feedback—what you liked, what could be improved, or any bugs you find. The test only takes a few minutes, and you’ll get early access to something I’m truly passionate about creating. 🌟 I’m incredibly grateful for any support or advice you can offer as I learn the ropes of app development. Feel free to DM me if you have any questions. Thanks a ton in advance! ā¤ļø
    🚫 2
  • g

    George Z

    12/03/2024, 7:49 PM
    Hi, I am writing some tests for a ViewModel using Mockk and I'd like to know you opinion. Is this a good way to test the
    isLoading
    state?
    Copy code
    @Test
        fun `loadMovies updates uiState.isLoading`() = runTest {
            coEvery { repository.getMovies(MovieCategory.DEFAULT) } coAnswers {
                delay(600)
                Resource.Success(emptyList())
            }
    
            assertFalse(viewModel.uiState.value.isLoading)
    
            viewModel.loadMovies(MovieCategory.DEFAULT)
    
            advanceTimeBy(200)
    
            assertTrue(viewModel.uiState.value.isLoading)
    
            advanceUntilIdle()
            assertFalse(viewModel.uiState.value.isLoading)
    
            coVerify { repository.getMovies(MovieCategory.DEFAULT) }
        }
    o
    • 2
    • 1
  • g

    groostav

    12/10/2024, 9:32 AM
    annoying problem (maybe actually solved with jvm's loosening of constructor rules in valhalla?): I want to create an exception instance. I already have its stack trace as a variable, so I want to create this exception, and then set its stack trace. I want to create a custom exception type for this purpose. What is the most idiomatic way to do this?
    Copy code
    class MyCustomException(val trace: List<StackTraceElement>): Exception(){
        init {
            stackTrace = trace.toTypedArray()
        }
    
        override fun fillInStackTrace() = this //interrupt call to dump back-trace into stack-trace
    }
    ?
    j
    h
    • 3
    • 5
  • p

    Paulo Cereda

    12/13/2024, 10:24 PM
    Friends, I had a great time trying to implement
    sleepsort
    in Kotlin. 😁 The best I could come up with is as follows (playground link):
    Copy code
    import kotlinx.coroutines.coroutineScope
    import kotlinx.coroutines.delay
    import kotlinx.coroutines.async
    import kotlinx.coroutines.awaitAll
    
    suspend fun main() {
        println(sleepsort(listOf(63, 32, 62, 14, 5)))
    }
    
    suspend fun sleepsort(list: List<Int>): List<Int> = coroutineScope {
        buildList {
            list.map { number ->
                async {
                    delay(number.toLong())
                    add(number)
                }
            }.awaitAll()
        }
    }
    Do you have any suggestions and/or improvements to make it better (or even worse)? Thank you so much, and season's greetings to everyone! šŸŽ„
    j
    r
    • 3
    • 4
  • d

    Daniel Pitts

    12/17/2024, 5:39 PM
    Updated version of my Json building DSL. Feedback requested. README.md
    Copy code
    import 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:
    Copy code
    {
      "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
    }
    c
    k
    d
    • 4
    • 10
  • e

    Edgar Avuzi

    12/22/2024, 7:45 AM
    Do you think if pipeline programming is good to put everywhere like this? I'm just so obsessed with it. It makes the code so clear, simple and straightforward. IMO. Like this: do steps one, two, three. And that's it. But one can say that the 3 usages of
    .let
    are redundant here (because there is no
    null
    to handle using
    ?.let
    ). Still this disadvantage does not outweight. IMO
    o
    a
    +2
    • 5
    • 7
  • a

    Ahmed

    01/17/2025, 10:04 AM
    For some reason the flow doesn't work as expected for my use case. More in 🧵
    s
    s
    • 3
    • 24
  • a

    arve

    01/21/2025, 1:26 PM
    Given a rather large 3rd party interface, I need to implement only a small handful methods. (for testing, i control the calling code)
    Copy code
    interface 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:
    Copy code
    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 šŸ˜ž
    Copy code
    // 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?
    e
    d
    • 3
    • 7
  • m

    Mark

    01/22/2025, 3:25 AM
    For producing a
    StateFlow
    from another
    StateFlow
    without requiring a
    CoroutineScope
    (so no new coroutine):
    Copy code
    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)
    }
    e
    • 2
    • 28
  • e

    Eugen Martynov

    02/10/2025, 8:11 AM
    Is there way to have method reference for optional receiver?
    Copy code
    customKeyListener?.onCustomKeyPressed()
    something like
    Copy code
    customKeyListener::onCustomKeyPressed
    e
    m
    • 3
    • 7
  • r

    Richard

    03/05/2025, 7:27 AM
    What do you think of that file - having the Extension function right below the enum?
    Copy code
    enum 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
        }
    j
    k
    +3
    • 6
    • 17
  • e

    Edgar Avuzi

    03/07/2025, 1:47 AM
    Hi, I recently started a small Kotlin project for the "Build Your Own Interpreter" challenge. It's purely for practice and has no open-source value. If you have time, I’d appreciate any feedback on Kotlin idioms, readability, and best practices. Tests aren’t fully implemented yet — I'll add them once the overall structure is settled. Thanks!
    k
    • 2
    • 1
  • m

    Mark

    03/08/2025, 2:20 PM
    I know it’s more standard to put
    Density
    as the receiver, but isn’t the API usage cleaner when doing this?
    Copy code
    fun TextUnit.scale(scale: Float, density: Density): TextUnit {
        if (this.isUnspecified) return this
        return with(density) {
            (scale * this@scale.toPx()).toSp()
        }
    }
    e
    z
    c
    • 4
    • 7
  • b

    Ben Madore

    03/11/2025, 1:31 AM
    I’ve got a conventions plugin, that has an extension containing a field:
    val 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?
    Copy code
    // 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)
        }
    }
    • 1
    • 2
  • c

    czuckie

    03/19/2025, 9:21 AM
    What are opinions on extensive use of extension functions/properties in codebases? I've recently started working on a new codebase and it feels like every file I look at has things like:
    Copy code
    private 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?
    h
    r
    c
    • 4
    • 11
  • v

    Vivek Modi

    04/04/2025, 9:21 PM
    Hey, I have a Profile UI where, when the user lands on the screen, I want to show a loading indicator while fetching the API response. If the request is successful, I display the user data; if not, I show an error message using a Flow. In the successful response, the user has three available actions: Delete Account, Change Password, and Logout. For Delete Account and Change Password, I need to navigate to another Compose screen, and I’m still using event flow for these actions. For Logout, I need to call an API. While the API call is in progress, I show a loading indicator, and stop it once the process is complete. On success, I clear the token and other relevant user data. In my ViewModel, I’m calling domain layer interfaces for login and profile operations. The data layer handles API requests, and both repositories return a Result. I combine these results using StateFlow.
    p
    • 2
    • 12
  • e

    Emre

    04/07/2025, 4:00 PM
    How can you define a ByteArray value class with a structural equals operator? Kotlin complains that Member with the name 'equals' is reserved for future releases.
    e
    • 2
    • 2
  • a

    Alex Kuznetsov

    04/11/2025, 5:51 PM
    Generally I'd use
    Language
    annotation on a String literal for syntax highlighting and such, for example
    Copy code
    @Language("SQL")
    val sql = "SELECT weight, name FROM boxes"
    But I'm reviewing code where parameters are annotated with it:
    Copy code
    `fun doSomething(@Language("JSON") payload: String) { ...
    why would we want to do that? what does it buy us?
    p
    k
    • 3
    • 5
  • s

    Sam Dukes

    04/16/2025, 8:52 AM
    Hi everyone, I've written an app which is intended to allow players of Tekken 8 to save combos they make in game or found online to allow them to practice while playing the game. I've used RoomDB & Datastore APIs for data persistence. I know there's definitely places I can improve but I would love it if someone was able to have a look at my code and give it a review. https://github.com/Dooques/FightingFlow Thanks in advance
    l
    • 2
    • 2
  • v

    Vivek Modi

    05/01/2025, 8:35 PM
    Hi I'm working on a
    Jetpack 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.
    • 1
    • 11
  • c

    czuckie

    05/02/2025, 12:28 PM
    am I being a dummy? the other local variables shouldn't be considered JSON just because I annotated a single local variable right?
    c
    h
    • 3
    • 6
  • a

    Alex Kuznetsov

    05/06/2025, 12:44 PM
    Is there a reason commonly used
    runCatching
    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?
    j
    • 2
    • 1