Richie
Richie

Reputation: 5199

Kotlin script - "extension method" is a member and an extension at the same time

I have Kotlin some code that works as a class but when I try and run it as a Kotlin script I am getting " error: 'getNameAndVersion' is a member and an extension at the same time. References to such elements are not allowed"

enum class Env { Test, Sit }

data class ImageVersions(val apiName: String, val versions: Map<Env, String?>)

fun String.getNameAndVersion() = substringBefore(':') to substringAfter(':')

val testList = listOf("api-car-v1:0.0.118", "api-dog-v1:0.0.11", "api-plane-v1:0.0.36")
val sitList = listOf("api-car-v1:0.0.119", "api-plane-v1:0.0.37", "api-dog-v1:0.0.12")

getVersions(
    mapOf(
        Env.Test to testList,
        Env.Sit to sitList
    )
).forEach(::println)
    
fun getVersions(envMap: Map<Env, List<String>>): List<ImageVersions> {
    val envApiNameMap = envMap.mapValues { it.value.associate(String::getNameAndVersion) }
    val allApiNames = envApiNameMap.flatMap { it.value.keys }.distinct()
    return allApiNames.map { apiName ->
        ImageVersions(apiName, envApiNameMap.mapValues { it.value[apiName] })
    }
}

I don't think I'm doing anything wrong with the way I'm using the method reference but according to my compiler I'm wrong. Appreciate some help with this. thanks

kotlinc -script .\myscript.kts
error: 'getNameAndVersion' is a member and an extension at the same time. References to such elements are not allowed 

Upvotes: 1

Views: 433

Answers (1)

Arpit Shukla
Arpit Shukla

Reputation: 10523

I don't have any experience with scripts but this error occurs when you try to reference a function inside a class that is also an extension function. (Here it is pointing to String::getNameAndVersion). Maybe when you run a script, the entire code is wrapped inside a class and then executed.

To fix this you can do one of the following:

  • Convert the function to a normal function which accepts a String parameter.
    fun getNameAndVersion(s: String) = s.substringBefore(':') to s.substringAfter(':')
    
    And replace String::getNameAndVersion with just ::getNameAndVersion in associate function
  • Other option is to directly call the function in the associate's lambda instead of passing a reference of this function.
    .associate { it.getNameAndVersion() }
    

Upvotes: 3

Related Questions