Running into an issue with Gradle and Kotlin Multiplatform: ```Execution failed for task ':mewsic-pl...
m

martmists

over 1 year ago
Running into an issue with Gradle and Kotlin Multiplatform:
Execution failed for task ':mewsic-plugin-api:compileDebugKotlinAndroid'.
> Error while evaluating property 'friendPathsSet$kotlin_gradle_plugin_common' of task ':mewsic-plugin-api:compileDebugKotlinAndroid'.
   > Could not resolve all files for configuration ':mewsic-plugin-api:debugCompileClasspath'.
      > Could not resolve com.google.guava:guava:33.2.1-android.
        Required by:
            project :mewsic-plugin-api
         > Cannot find a version of 'com.google.guava:guava' that satisfies the version constraints:
              Dependency path 'dev.uninit:mewsic-plugin-api:1.0.0' --> 'com.google.guava:guava:33.2.1-android'
              Dependency path 'dev.uninit:mewsic-plugin-api:1.0.0' --> 'com.google.guava:guava:33.2.1-jre'
              Constraint path 'dev.uninit:mewsic-plugin-api:1.0.0' --> 'com.google.guava:guava:{strictly 33.2.1-android}' because of the following reason: version resolved in configuration ':mewsic-plugin-api:debugRuntimeClasspath' by consistent resolution
With gradle code (in
kotlin { sourceSets {
)
androidMain {
    dependencies {
        implementation("com.google.guava:guava:${Versions.guava}-android")
    }
}

appMain {  // Shared between androidMain and desktopMain
    dependencies {
        compileOnly("com.google.guava:guava:${Versions.guava}-jre")  // CompileOnly because the artifact differs between Android and Desktop
    }
}

desktopMain {
    dependencies {
        implementation("com.google.guava:guava:${Versions.guava}-jre")
    }
}
I have a use case for inferring nested generic types in a function's definition. Consider the follo...
i

Isaac Udy

over 3 years ago
I have a use case for inferring nested generic types in a function's definition. Consider the following code:
interface Input<T>  { ... }
interface Output<T> { ... }
fun <In: Input<T>, T> registerForOutput(): Output<T> { ... }
Based on the type of
In
, I want to be able to use
registerForOutput
to create an
Output
instance of the same generic type. In this situation, I refer to
T
as the "nested generic type of `In`" in the context of
registerForOutput
. To re-word the initial sentence: I want
registerForOutput
to return an
Output
with the nested generic type of
In
. Consider the following code:
class ConcreteInput : Input<String> { ... }
val output = registerForOutput<ConcreteInput, String>()
The code above provides a developer experience that is not ideal. A developer, despite knowing that
ConcreteInput
uses
String
as the generic type for its implementation of
Input
, still needs to explicitly define
String
as a secondary generic type of the call to
registerForOutput
. This is only a minor inconvenience in the case that
Input
has a single generic type, but in the case that
Input
has two, three, or even more generic types, this becomes significantly less enjoyable to work with. I believe that this could be improved by including an "inferred" keyword, which is usable within generic type definitions. Consider the following code:
fun <In: Input<inferred T>> registerForOutput(): Output<T> { ... }
In the code above, we state that
T
, the generic type of the generic
In
(the "nested generic" of
In
) should be inferred by the compiler, meaning that it would be possible to write the following code, where the type out
output
should be `Output<String>`:
val output = registerForOutput<ConcreteInput>()
The following code should infer that the
T
of
registerForOutput
is
Int
, and the type of
output
should be `Output<Int>`:
val output = registerForOutput<Input<Int>>()
The following code should infer that the
T
of
registerForOutput
is
Nothing
, and the type of
output
should be `Output<Nothing>`:
val output = registerForOutput<Input<*>>()
Ideally, the
inferred
keyword that I am suggesting should be compatible with
reified
, so that it's possible to write the following:
inline fun <In: Input<inferred reified T> registerForOutput(): Output<T> {
    println(T::class.java.simpleName)
    ...
}
I am interested to hear feedback on whether or not this makes sense (or is possible) as a language feature!
âž• 2