Open bric3 opened 1 year ago
Oh actually there's one with the objective c plugin. But stil it would be nice to have in the C plugins.
You are right; we should expand the samples. As for making the DSL more friendly to Kotlin, we aren't Kotlin experts. If you could help us by pointing out the Kotlin concept for these types of Kotlin-friendly methods, we can look into adding them.
Mhh about kotlin friendly API, this might require writing kotlin code. For example the method withType
on the task container have this Java API,
DomainObjectCollection {
// ...
<S extends T> DomainObjectCollection<S> withType(Class<S> type, Action<? super S> configureAction);
}
and usable in Groovy DSL or Kotlin DSL
```groovy tasks.withType(JavaExec) { } ``` | ```kotlin tasks.withType(JavaExec::class.java) { } ``` |
However to improve the friendliness of the kotlin DSL API
tasks.withType<JavaExec>() {
}
There are extension function
inline fun <reified S : Any> DomainObjectCollection<in S>.withType(noinline configuration: S.() -> Unit) =
withType(S::class.java, configuration)
This function declaration might be daunting at first as there are 6 different concepts there
inline
, in Kotlin an inline function tells the compiler to put the bytecode instructions where the method is referenced. This function is like a C/C++ macro.
<reified S : Any>
this is a generic declaration, equivalent to <S extends Object>
(Any
in kotlin is an alias to Object
) ; the reified
keyword means the generic information is not erased as in Java, however this require the function to be inline
.
DomainObjectCollection<in S>
is the reference to the generic variable, and is somewhat equivalent to DomainObjectCollection<? super S>
in Java
noinline configuration: S.() -> Unit
, the no inline simply indicates the compiler to not inline the body of the lambda. The lambda has the type S.() -> Unit
. There's no type between the parenthesis ()
, so there's no args and Unit
is like void
in Java, so this is equivalent to a Java Runnable
; the interesting bit here is S.()
, it means S
is the receiver type meaning that this
within the lambda is of type S
. The receiver type are really powerful to write convenient DSLs.
https://kotlinlang.org/docs/lambdas.html https://kotlinlang.org/docs/lambdas.html#function-literals-with-receiver
... fun ... .withType(...) = withType(S::class.java, configuration)
means this function has a single statement, and as such kotlin offer a short hand =
instead of writing { return withType(S::class.java, configuration) }
; also note the return type can be omitted in this declaration just like var s = "Hello"
can be omitted in Java.
https://kotlinlang.org/docs/functions.html#single-expression-functions
S::class.java
Like in groovy kotlin has it's own class reference and in order here to link to the right java API, it is necessary to access the Java Class
. In this function this notation works because S
is reified
.
https://kotlinlang.org/docs/reflection.html#class-references
Additionally there's a 6th concept on the "callsite", in kotlin if the last parameter is a lambda it can be written outside the method ; this should be similar to Groovy. Both notation ate the same
tasks.withType<JavaExec>({ })
tasks.withType<JavaExec>() {
}
Thanks a lot for the information. I will see what I can do about that.
For example in Kotlin DSL
Also I wonder if the API could be make more kotlin friendly, so one could write