vert-x3 / vertx-lang-kotlin

Vert.x for Kotlin
Apache License 2.0
296 stars 68 forks source link

Document using vertx-lang-kotlin-gen to generate suspending methods #159

Closed rgmz closed 1 year ago

rgmz commented 4 years ago

A faux pas on my part, but I have been using Vert.x with Kotlin Coroutines (💖) for almost a year and only just realized that it's possible to generate suspending methods for my own project.

The documentation mentions that:

...Vert.x generates suspending extension methods for all its asynchronous methods.

But it should mention the use of vertx-lang-kotlin-gen with kapt as well.


Gradle

dependencies {
  kapt "io.vertx:vertx-lang-kotlin-gen:$vertxVersion"
  ...
}

Maven https://kotlinlang.org/docs/reference/kapt.html#using-in-maven Include vertx-lang-kotlin-gen as an annotationProcessorPath:

<annotationProcessorPath>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-lang-kotlin-gen</artifactId>
  <version>${vertx.version}</version>
</annotationProcessorPath>
dangfan commented 4 years ago

Hi @rgmz , I've added the vertx-lang-kotlin-gen in my gradle file. Here is some of my interface:

@ProxyGen
@VertxGen
public interface LiveDatabaseService {
  @Fluent
  LiveDatabaseService createLiveEntry(String streamName, Handler<AsyncResult<Long>> resultHandler);

But it didn't generate the corresponding Await methods in the generated path. Did I miss anything?

Thanks!

rgmz commented 4 years ago

But it didn't generate the corresponding Await methods in the generated path. Did I miss anything?

@dangfan Is vertx-codegen also defined for kapt?

kapt "io.vertx:vertx-codegen:$vertxVersion"
dangfan commented 4 years ago

But it didn't generate the corresponding Await methods in the generated path. Did I miss anything?

@dangfan Is vertx-codegen also defined for kapt?

kapt "io.vertx:vertx-codegen:$vertxVersion"

Yes, my build.gradle is like this:

plugins {
  id 'java'
  id 'application'
  id 'org.jetbrains.kotlin.jvm' version '1.3.71'
  id 'org.jetbrains.kotlin.kapt' version '1.3.71'
}

dependencies {
  kapt "io.vertx:vertx-codegen:$vertxVersion:processor"
  kapt "io.vertx:vertx-service-proxy:$vertxVersion:processor"
  kapt "io.vertx:vertx-lang-kotlin-gen:$vertxVersion"

// other dependencies
}
vietj commented 3 years ago

note that in vert.x 4 we still allow but discourage generating suspending methods. Service proxies in a next release will allow to write the service using futures instead of callback and that works nicely with coroutines

vietj commented 3 years ago

that might be the reason why we would not add it to the documentation.

hbrackel commented 3 years ago

Why would a future generator not generate kotlinesque suspending methods? A typical "reactive" interface in Kotlin looks like

suspend fun doSomething(param1:T) : S or fun doSomethingStreaming(param2:R) : Flow<S>

Their behind the scenes implementation could still call await() on a future. Otherwise, another manual API layer would be needed to get a convenient Kotlin API (calling .await() is possible but not really the Kotlin way - which is NOT to expose futures)

vietj commented 3 years ago

because now vertx method return a future and you can write

somethinAsync().await()

instead of

somethingAsyncAwait()

so we prefer to avoid generating such code in practice.

Of course service-proxies cannot do that yet (they need to use Handler) but in 4.1 we would like to have service proxies able to return a Future

On Mon, Feb 8, 2021 at 3:27 PM hbrackel notifications@github.com wrote:

Why would a future generator not generate kotlinesque suspending methods? A typical "reactive" interface in Kotlin looks like

suspend fun doSomething(param1:T) : S or fun doSomethingStreaming(param2:R) : Flow

Their behind the scenes implementation could still call await() on a future. Otherwise, another manual API layer would be needed to get a convenient Kotlin API (calling .await() is possible but not really the Kotlin way - which is NOT to expose futures)

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/vert-x3/vertx-lang-kotlin/issues/159#issuecomment-775187362, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABXDCS7KJTZHU3PZOOZRIDS57YFZANCNFSM4JWHKE4Q .

hbrackel commented 3 years ago

when using the vertx API calls to do sequential processing, as in

launch(vertx.dispatcher()){
    val a = doFirstThing() // eventbus call
    val b = doSecondThing(a) // evenbus call
}

you would want suspending functions. You could certainly also write (in case of futures)

launch(vertx.dispatcher()){
    val a = doFirstThing().await() // eventbus call
    val b = doSecondThing(a).await() // evenbus call
}

but this doesn't provide the best Kotlin experience (at least not IMO)

vietj commented 3 years ago

so you are saying taht we should continue supporting the generation of extension methods for coroutines ?

On Mon, Feb 8, 2021 at 4:00 PM hbrackel notifications@github.com wrote:

when using the vertx API calls to do sequential processing, as in

launch(vertx.dispatcher()){ val a = doFirstThing() // eventbus call val b = doSecondThing(a) // evenbus call }

you would want suspending functions. You could certainly also write (in case of futures)

launch(vertx.dispatcher()){ val a = doFirstThing().await() // eventbus call val b = doSecondThing(a).await() // evenbus call }

but this doesn't provide the best Kotlin experience (at least not IMO)

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/vert-x3/vertx-lang-kotlin/issues/159#issuecomment-775209166, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABXDCTH23UGBJUYZS3SZK3S574A3ANCNFSM4JWHKE4Q .

rgmz commented 3 years ago

so you are saying taht we should continue supporting the generation of extension methods for coroutines ?

It's worth noting that the Kotlin team prefers .await() extension methods over things like ...methodAwait() or ...methodAsync().

https://www.youtube.com/watch?v=_hfBv0a09Jc

hbrackel commented 3 years ago

For all of my vertx use cases (I exclusively use Kotlin) I'd vote for coroutine extension methods. The option of calling .await() on futures still remains available as one can use the generated Java code from Kotlin as well.

A little of topic, so just a quick mention: it would also be very nice to have a suspend handle() method option similar to the start() and start(future) available in the service stub. The handle() method usually also processes steps sequentially.

vietj commented 3 years ago

I'm open to anything :-)

I believe that for Vert.x code we want to remove generation and have ppl use .await()

but for users, I believe we should give them freedom to chose.

On Mon, Feb 8, 2021 at 4:50 PM Richard Gomez notifications@github.com wrote:

so you are saying taht we should continue supporting the generation of extension methods for coroutines ?

It's worth noting that the Kotlin team prefers .await() extension methods over things like ...methodAwait() or ...methodAsync().

https://www.youtube.com/watch?v=_hfBv0a09Jc

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/vert-x3/vertx-lang-kotlin/issues/159#issuecomment-775244801, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABXDCQ2BJEARQEE4A3Q6Z3S6AB5ZANCNFSM4JWHKE4Q .

hbrackel commented 3 years ago

so you are saying taht we should continue supporting the generation of extension methods for coroutines ?

It's worth noting that the Kotlin team prefers .await() extension methods over things like ...methodAwait() or ...methodAsync().

https://www.youtube.com/watch?v=_hfBv0a09Jc

That's absolutely true - for async calls

rgmz commented 3 years ago

so you are saying taht we should continue supporting the generation of extension methods for coroutines ?

It's worth noting that the Kotlin team prefers .await() extension methods over things like ...methodAwait() or ...methodAsync(). https://www.youtube.com/watch?v=_hfBv0a09Jc

That's absolutely true - for async calls

Indeed.

@hbrackel out of curiosity, are you using Vert.x purely with Kotlin or relying on things like Service Proxies?

I tend to only use Kotlin + Kotlin Coroutines, and avoid @VertxGen whenever possible.

Therefore, my code tends to be normal classes with suspend methods wrapped in coroutineScope:

// MainVerticle.kt
class MainVerticle : CoroutineVerticle() {

  override suspend fun start() {
     super.start()

    val client = Client(vertx)
    println("Result is '${client.foo()}'")
  }
}

// Client.kt
class Client(private val vertx: Vertx) : CoroutineScope by CoroutineScope(vertx.dispatcher()) {
  suspend fun foo(): String = coroutineScope {
    // normal code written like kotlin Coroutines
    println("Doing thing...")
    delay(1000L)
    "bar"
   }
}
hbrackel commented 3 years ago

@rgmz at this time, I write all code the same way as you do, exclusively Kotlin, no @VertxGen. But as I am dealing with many verticle based services, I am a little tired of the boilerplate (particularly on the server / handler side; message composition, error handling, ...) plus I'd like to use the (vertx) service discovery. I did not see any benefit in using the Vertx code gen feature, because the Kotlin API didn't look like I needed or wanted it. I also use most of the vertx services in conjunction with Spring and would appreciate a similar reactive API (see above) to access services, irrespectively of their implementation

tsegismont commented 1 year ago

Closing: Vert.x does not generate xxxAwait methods anymore.