I have a DSL function whose lambda returns `Any?` ...
# dsl
j
I have a DSL function whose lambda returns
Any?
allowing any object to be returned. This lambda's receiver is also a DSL type meaning there are functions you can call inside of it. The problem is that these functions return
Unit
thus completing the contract of the enclosing lambda and avoiding the need to actually return an object. Is there any way to avoid this?
Copy code
@MyDsl interface Foo {
  fun bar(lambda: Bar.() -> Any?)
}
@MyDsl interface Bar {
  fun someHelper(size: Int)
  fun otherHelper(flag: Boolean)
}

bar {
  someHelper(2)
  otherHelper(true)
  // should be required to return an object here
}
I tried to get clever with an overload of
bar
whose lambda returned
Unit
and was marked as an error, but you can't
@JvmName
an interface function. converting it to a class results in the
Unit
-returned lambda always being preferred. There's a Kotlin-internal annotation to lower its overload precedence, but I don't have access to that.
s
I got a bit further by taking both
Any?
and
Unit
methods out of the interface letting you
JvmName
them it seems return type inference isnt quite up to it.
Copy code
@MyDsl interface Foo {
    fun internalMethod()
}
@JvmName("asdasd")
@Deprecated("You must return something", level = DeprecationLevel.ERROR)
fun Foo.bar(lambda: Bar.() -> Unit) = Unit

@JvmName("asd")
fun Foo.bar(lambda: Bar.() -> Any?){
    internalMethod()
}


@MyDsl interface Bar {
    fun someHelper(size: Int)
    fun otherHelper(flag: Boolean)
}

fun Foo.f() {
    bar {
        someHelper(2)
        otherHelper(true)
        // should be required to return an object here
        "2"
    }
}
Best I got was something like this:
Copy code
@MyDsl interface Foo {
    fun internalMethod()
}

@JvmName("asd")
fun <R> Foo.bar(lambda: Bar.() -> R){
    internalMethod()
}


@MyDsl interface Bar {
    fun someHelper(size: Int)
    fun otherHelper(flag: Boolean)
}

fun Foo.f() {
    bar<String> {
        someHelper(2)
        otherHelper(true)
        // should be required to return an object here
//        "2"
    }
}