Can we support that? :smile: I’d like to return a...
# language-proposals
m
Can we support that? 😄 I’d like to return a lambda from a function which can be immediately invoked just like a trailing lambda. Unfortunately it cannot be invoked unless I assign it to a variable first, or call
invoke
or put it into parenthesis. Neither make for a good DSL. At the moment to work around that limitation I always have to add two functions: • one that returns a lambda • one that accepts a trailing lambda for immediate invocation and returns
Unit
b
You can also call it like this:
Copy code
(test(1)) {
    println(it)
}
m
Yes, that’s what I’ve mentioned. That’s not a good DSL/usability though and I think it can be improved.
r
Here is an alternative
Copy code
class test(val value: Int, val f: (Int) -> Unit) {
  init {
    f(value * 2)
  }
}

fun main() {
  test(1) {
    println(it)
  }
}
prints 2
m
Yes, that the work around that I’ve mentioned. Now you have to write two
test
functions: one that returns something invokable and one that directly takes and invokes the lambda. If you have a lot of cases like that (and I have plenty) it adds to a lot of unnecessary and repetitive code.
e
What's the motivation for this request? What kind of DSL are you trying to build that requires this kind of "functions returning functions" design?
m
I’m building a Gradle DSL-like component configuration framework, where the following would be equivalent:
Copy code
sourceSets.named("main").resources.srcDir("resources")
Copy code
sourceSets {
   named("main") {
      resources {
         srcDir("resources")
      }
   }
}
Module creators create configurable components and write related DSL by providing for example
Copy code
val ComponentSet<Project>.sourceSets: ComponentSet<SourceSet>
…
fun ComponentSet<SourceSet>.named(name: String): ComponentSet<SourceSet>
…
val ComponentSet<SourceSet>.resources: ComponentSet<SourceDirectorySet>
…
fun ComponentSet<SourceDirectorySet>.srcDir(path: String)
Everything is configured lazily using
ComponentSet
which will configure 0 or more components of the specified type.
ComponentSet<Component>
has an
operator fun invoke(configure: ComponentSet<Component>.() -> Unit)
to lazily apply a configuration to the set of components. Properties and functions return such a
ComponentSet
and DSL users can decide whether they want to chain (
a.b.c { … }
) or nest (
a { b { c { … }}}
) depending on their need/use case. I want component writers to not have to duplicate every single configuration function (one lambda
val
and one
fun
that takes lambda) but only write each property/function exactly once.
Here an example from the unit tests I’m currently working on.
Here’s another example