Hello, i was wondering if there is some known issu...
# arrow
a
Hello, i was wondering if there is some known issue that one should not use kotlin:2.0.0 with arrow-1.2.4 already? I tried to upgrade and play around a bit but it seems that i ran into a issue. For some reason when i change to kotlin:2.0.0 the following block gives an error (not in IDE only when running a test or compiling). Changing back to 1.9.24 makes it run again
Copy code
context(ResourceScope)
suspend fun initDependencies() =
    either {
        val env = env()
        val client: HttpClient = autoCloseable { httpClient() }
        ...
    }
}

--> Type mismatch: inferred type is 'arrow.fx.coroutines.Resource<A>', but 'io.ktor.client.HttpClient' was expected.
s
Hey @albrechtroehm, That should not be the case 🤔 I've updated several projects to 2.0, without running into this issue. Let me double check one of my projects.
a
that's weird... but it's possible given the changes in type inference in K2
could you maybe share a bigger snippet? I can have a bigger look and maybe report to the compiler team if this is really a regression
💚 2
also, does it work if you use
ResourcrScope.initDependencies()
instead of a context receiver?
a
Let me check
s
Works fine for me in Kotlin 2.0, with Arrow 2.0.0-alpha.3 and 1.2.4. Both context receivers, and extension receiver.
a
Extension method works fine
a
I feel like we need to see a bit more of the code to understand where the problem lies... also, what is the inferred type of
initDependencies()
?
a
Bigger snippet: (edit changed it back to the failing with context receiver)
Copy code
fun main() =
    SuspendApp {
        val logger = LoggerFactory.getLogger("ktor.application")
        logger.info("Starting application...")
        either {
            resourceScope {
                val deps = initDependencies()
                heartbeat().onEach { processEvent(deps) }.launchIn(this@SuspendApp)
                awaitCancellation()
            }
        }.onLeft { error -> logger.error(error.toString()) }
    }

context(ResourceScope, Raise<Problem>)
suspend fun initDependencies(): Deps {
    val env = env()
    val client: HttpClient = autoCloseable { httpClient() }
    val mattermostClient = mattermostClient(client, env)
    val quotesService = QuotesService()
    val reminderService = ReminderService(quotesService, mattermostClient)

    return Deps(reminderService)
}

class Deps( val reminderService: IReminderService)
Errors • Initializer type mismatch: expected ‘io.ktor.client.HttpClient’, actual ‘arrow.fx.coroutines.Resource<ERROR CLASS: Cannot infer argument for type parameter A>’. • Type mismatch: inferred type is ‘arrow.fx.coroutines.Resource’, but ‘io.ktor.client.HttpClient’ was expected.
s
httpClient
is not coming from Ktor here, right? What does the
httpClient
function look like?
a
Copy code
import de.roehm.serialization.registerJacksonConverter
import io.ktor.client.HttpClient
import io.ktor.client.engine.okhttp.OkHttp
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.plugins.logging.*
import io.ktor.client.plugins.logging.LogLevel
import io.ktor.client.plugins.logging.Logging

fun httpClient(logging: Boolean = true) =
    HttpClient(OkHttp) {
        expectSuccess = false
        install(ContentNegotiation) {
            registerJacksonConverter()
        }

        if (logging) {
            install(Logging) {
                logger = Logger.SIMPLE
                level = LogLevel.ALL
            }
        }
    }
s
Okay, nothing strange but might be fixed by explicitly specifying the return type here.
fun httpClient(logging: Boolean = true): HttpClient
, if that's the case, then its probably a compiler bug indeed.
a
Tried it, not fixing it for me
😫 1
Copy code
Also seems to be unrelated to httpClient()

context(ResourceScope, Raise<Problem>)
suspend fun initDependencies(): Deps {
    val env = env()
    val test: Tester = autoCloseable { getTester() }
}

fun getTester() : Tester = Tester()

class Tester: AutoCloseable{
    override fun close() {
        TODO("Not yet implemented")
    }
}
--> Initializer type mismatch: expected 'de.roehm.client.Tester', actual 'arrow.fx.coroutines.Resource<ERROR CLASS: Cannot infer argument for type parameter A>'.
edit: also with explicit type on getTester()
🤯 1
a
maybe it's using a differtent
autoCloseable
?
a
Can you reproduce this? or can i provide more information what is missing? When i follow
autoCloseable
i end up in ResourceExtension.kt:141 (arrow-fx-coroutines-jvm-1.2.4.jar), but IDE is happy so might not be actually true?' Removed some more noise, this is enough to produce the error for me.
Copy code
import arrow.fx.coroutines.ResourceScope
import arrow.fx.coroutines.autoCloseable
import arrow.fx.coroutines.resourceScope
import kotlinx.coroutines.runBlocking

fun main() =
    runBlocking {
        resourceScope {
            val deps = initDependency()
        }
    }

context(ResourceScope)
suspend fun initDependency(): Tester {
    val test: Tester = autoCloseable { getTester() }
    return test
}

fun getTester() : Tester = Tester()

class Tester: AutoCloseable{
    override fun close() {
        TODO("Not yet implemented")
    }
}
s
I can reproduce it @albrechtroehm using that snippet. Strange indeed, IDEA is happy. I'm on Kotlin 2.0.0, and Arrow 2.0.0-alpha.3 but only when using context receivers.
a
Good to hear that you can reproduce it! At least it’s not just a weird thing at my end and I did not waste your time 😅
a
I am 90% sure about where the problem comes from: • we have two versions of
autoCloseable
, one that works inside
ResourceScope
and returns
A
, one which works outside of it and returns
Resource<A>
• the compiler prioritizes the one with an extension receiver if you are inside of that implicit scope; this is why moving
ResourceScope
from context to receiver fixes the problem • however, the rules for context receivers are not set in stone; so they may have been unadvertedly changed, giving now more priority to the
autoCloseable
without it, which returns
Resource<A>
😰 2
my suggestion is to avoid context receivers at this point and work with
ResourceScope.foo()
as far as you can
👍 1
s
Should we consider deprecating an API? This seems very confusing.
Deprecating, and providing an alias within 2.x.x seems okay here for a confusing scenario like this.
a
yeah, maybe we should try to avoid these scenarios (I think that something similar happened with
saga
)
💯 3
s
Yes, I've been thinking about this in
saga
for a while. I liked the duality, but you warned me 😅 😅 Saga could be fixed by deprecating
saga { }.transact()
and providing a
sagaScope
alias.
👍 1