My question is slightly tongue in cheek, it's obviously messing around in the fringes of the language design :)
Well here is my actual motivating example … it’s using type safe builders to do pretty printing …
import java.util.ArrayList
abstract class AST {
protected fun PrettyPrinter.listInBrackets(items: List<String>) {
+“(”; +items.makeString(); +“)”
}
abstract fun pretty(): String
}
class MethodAST(val name: String, val formalParams: List<String>): AST() {
override fun pretty() = prettyPrinter {
+"fun "; +name; listInBrackets(formalParams)
}
}
fun prettyPrinter(f: PrettyPrinter.() -> Unit): String {
val printer = PrettyPrinter()
printer.f()
return printer.toString()
}
class PrettyPrinter {
val output: ArrayList<String> = arrayListOf()
fun String.plus() { output.add(this) }
fun toString() = output.makeString(“”)
}
fun main(args: Array<String>) {
val method = MethodAST(“foo”, listOf(“a”, “b”, “c”))
println(method.pretty())
}
The above works fine. Note that this is a bit overkill for just producing strings … but for the actual code I’m working with I have a much richer return representation than String so it’s worth the effort.
Now the interesting bit is the extension method in AST: listInBrackets. Note that ‘listInBrackets’ is not defined inside PrettyPrinter, that’s because the pattern in ‘listInBrackets’ is common to my ASTs, but it doesn’t necesarily belong in the much more general PrettyPrinter library.
So what I’m curious to know is whether you can achieve this:
class MethodAST(val name: String, val formalParams: List<String>): AST() {
override fun pretty() = prettyPrinter {
+"fun "; +name; formalParams.inBrackets()
}
}
Now you can obviously do this by moving the ‘inBrackets’ method into the PrettyPrinter class …
class PrettyPrinter {
val output: ArrayList<String> = arrayListOf()
fun String.plus() { output.add(this) }
fun toString() = output.makeString(“”)
fun List<String>.inBrackets() { +“(”; +this.makeString(); +“)” }
}
But I don’t want to do that ‘inBrackets’ is specific to my AST classes, it doesn’t belong in PrettyPrinter! What I want to do is define it in the AST class …
abstract class AST {
protected fun PrettyPrinter.List<String>.inBrackets() {
+"("; +this.makeString(); +")"
}
abstract fun pretty(): String
}
Hence the question: can you define an extensions to class List<String> as a member of class PrettyPrinter, inside class AST? I strongly suspect the answer is no.
And its fine if the answer is ‘no’, clearly none of this is strictly necessary for my purposes: the solution at the top of the page works well enough. I doubt many people will run into difficulty if it is impossible to define “member extensions” as extensions, it’s probably not even worth the extra syntax clutter that it would introduce. Still the lack of orthogonality is slightly grating