Operator for unknown method call

Very useful for DSL-s ability delegate unknown method calls to special operator, maybe like this:

data class XmlAttribute(val name: String, val value: String)
data class XmlNode(val name:String, val children:List<XmlNode>, val attributes:List<XmlAttribute>)

class XmlNodeBuilder(val name:String) {

    private val attributes = ArrayList<XmlAttribute>()
    private val children = ArrayList<XmlNode>()

    operator fun unknownMethodCall(name:String, nodeBuilder: XmlNodeBuilder.()->Unit) {
        this.children.add(xmlNode(name, nodeBuilder))
    }

    operator fun unknownMethodCall(name:String, value:String) {
        this.attributes.add(XmlAttribute(name, value))
    }

    fun build():XmlNode = XmlNode(name, children, attributes)
}

fun xmlNode(name:String, nodeBuilder: XmlNodeBuilder.()->Unit):XmlNode {
    return XmlNodeBuilder(name).apply(nodeBuilder).build()
}

fun main(args: Array<String>) {
    xmlNode("root") {
        child {  // compile ok and delegate to unknownMethodCall("child", {...})
            someAttribute("attribute value") // compile ok and delegate to unknownMethodCall("someAttribute", "attribute value")
        }
        
        child("bla-bla") { // compile error, no methods with applicable signature
            // ...
        }
    }
}
1 Like

It is already (almost) possible with the invoke operator on strings: "child" { ... }

class XmlNodeBuilder {
    operator fun String.invoke(nodeBuilder: XmlNodeBuilder.()->Unit) {}
}

fun main(args: Array<String>) {
    xmlNode {
        "child" {  
         }
    }
}

I know about this ability (it used in gradle), it looks dirty a little, but of course much better than nothing.