Hi, when creating an inherited class within a func...
# compiler
h
Hi, when creating an inherited class within a function that refers to properties of the parent scope, it creates a constructor which is somehow reported to be-zero arg, but when creating an instance, it turns out it is not:
Copy code
import kotlin.reflect.KClass


open class Provider {

    open fun computeSmthg() = 42
}

class ConfigBuilder(val other: Int = 32) {

    fun asProvider(): KClass<*> {

        class CustomProvider : Provider() {

            override fun computeSmthg(): Int {
                return other
            }
        }

        return CustomProvider::class
    }
}

fun main() {

    val providerClass = ConfigBuilder().asProvider()

    require(providerClass.constructors.first().parameters.isEmpty())

    val constructor = providerClass.constructors.first()
    println(constructor.parameters)
    println(constructor)

    println(constructor.call())
}
which fails with
Copy code
fun <init>(): com.systema.nexperia.epi.solver.`ConfigBuilder$asProvider$CustomProvider`
Exception in thread "main" java.lang.IllegalArgumentException: Callable expects 1 arguments, but 0 were provided.
Could I rewrite the code from above to actually create CustomProvider with a zero-arg constructor while referring to
òther
property?
Not really what I was hoping for but with
kotlin-scripting-jsr223
we can simply compile the class in place with the value using
Copy code
class ConfigBuilder(val other: Int = 32) {

    fun asProvider(): KClass<*> {
        return with(ScriptEngineManager().getEngineByExtension("kts")) {
            eval(
                """
                     import com.systema.nexperia.epi.solver.Provider
                                
                     class CustomProvider : Provider() {
            
                        override fun computeSmthg(): Int {
                            return ${other}
                        }
                    }
                    
                    CustomProvider::class
                """
            ) as KClass<Provider>
        }
    }
}
By doing so we can build the type with the value from outer scope, while maintaining an zero argument constructor
t
Hi, constructor calls are a bit special, you cannot simply call them as functions. For example, in Java the virtual machine instruction is different for a constructor call than a simple function call. Basically, The constructor needs a class as "parameter" to be able to make an instance. I'm just guessing but I think that the exception you've got has nothing to do with the scope, it's more about the way you try to call the constructor. I feel that you do not need all this "class magic" to do what you actually want to do. Using Kotlin scripting actually feels the "worst possible way". What is the use case for your
CustomProvider
class?
One more thing: if you really want this "define a class inside a function" pattern you could return with a function that actually creates an instance of the class:
Copy code
fun asProvider() : () -> Provider {
   ...
   return { CustomProvider() }
}

...

ConfigBuilder().asProvider().doSomething()
Still feels quite wrong, but is probably better that the scripting call (which brings up the whole compiler toolchain during runtime, introduces a lot of security problems... brrrr...).
Based on the example, the good way could be to make provider an interface and make
ConfigBuilder
implement that interface. No need for
CustomProvider
.