utybo / Tegral

🟣 A Kotlin framework for web applications, cool libraries that go along with it!
https://tegral.zoroark.guru
Apache License 2.0
38 stars 4 forks source link

Explore the possibility of "functional definitions" in DI #65

Open utybo opened 1 year ago

utybo commented 1 year ago

The idea is to be able to define DI components as functions. This would unlock more advanced use cases, an obvious one being easier definition of simple web controllers and Ktor modules.

Usage

Here's an example of what this could look like.

Tegral Web Controllers

For example:

class GreeterService {
    fun greet(name: String): String {
        return "Hello, $name!"
    }
}

@TegralDiFundef
fun Application.openApiModule() {
    describe {
        title = "My greeter API"
    }
}

@TegralDiFundef
fun Routing.controller(gs: GreeterService) {
    get("/greet/{name}") {
        call.respondText(gs.greet(call.parameters["name"]!!))
    }
}

fun main() {
    tegral {
        install(OpenApiFeature)
        put(::openApiModule)
        put(::controller)
    }
}

Tegral DI


class GreeterService {
    fun greet(name: String): String {
        return "Hello, $name!"
    }
}

@TegralDiFundef
fun greetWorld(gs: GreeterService) {
    return gs.greet("World")
}

fun main() {
    val env = tegralDi {
        put(::GreterService)
        put(::greetWorld)
    }
    val fundef = env.getOrNull<Fundef>(ofFunction(::greetWorld))
    fundef.function // == ::greetWorld
    fundef() // == greetWorld(...)
}

Pros, cons and remarks

Pros

Indentiation

Saves an indentation space for controllers and modules and significantly simplifies their definition.

class HelloController : KtorController() {
    override fun Routing.install() {
        get("class") {
            call.respondText("Hello World!")
        }
    }
}

@TegralDiFundef
fun Routing.helloController() {
    get("fun") {
        call.respondText("H:ello World!")
    }
}

fun main() {
    tegral {
        put(::GreterService)
        put(::HelloController)
        put(::helloController)
    }
}

Ktor modules

Misc.

Cons

Qualifiers


class GreeterService {
    fun greet(name: String): String {
        return "Hello, $name!"
    }
}

@TegralDiFundef
fun greetWorld(gs: GreeterService) {

}

fun main() {
    val env = tegralDi {
        put(::GreterService, named("Hellofy"))
        put(
            (::greetWorld).toFundef {
                qualifyParameter("gs", named("Hellofy"))
            }
        )
    }
}

Remarks

Todo list

utybo commented 1 year ago

Idea for the step 3 of this whole plan, I think it would be better if we use the following behavior.

In cases where we could have a fundef: