Is it possible to avoid function names at all in Kotlin DSL? - kotlin

In Kotlin DSL example they use plus signs to implement raw content inserting:
html {
head {
title {+"XML encoding with Kotlin"}
}
// ...
}
Is it possible to define "nameless" functions in receiver to be able to write
html {
head {
title {"XML encoding with Kotlin"}
}
// ...
}
Are there any plans to do so in future versions of Kotlin?
Is there such things in languages, other than Kotlin?

I can think of two solutions to your problem:
Make the lambda with receiver return a String:
fun title(init: Title.() -> String) {
val t = Title().apply {
children.add(TextElement(init()))
}
children.add(t)
}
You can now call the title as suggested in OP. Actually this seems to be overhead in this particular scenario though and I'd recommend the following.
Create another title method that takes a String directly:
class Head : TagWithText("head") {
fun title(init: Title.() -> Unit) = initTag(Title(), init)
fun title(text: String) {
val t = Title().apply {
children.add(TextElement(text))
}
children.add(t)
}
}
Used like this:
head {
title("XML encoding with Kotlin")
}

Related

Which are the advantatges of using Template in Ktor in HTML DSL?

I've just started learning Ktor, and I really like the use of the HTML DSL. Reading the docs (https://ktor.io/docs/html-dsl.html#templates) I've seen that there is a Templates engine. However, either there is something that I can't see, or I don't find the advantages of using it. Isn't cleaner and easier to use standard Kotlin extension functions, like the Div, P,... instead?
I post an example of how I would write the example on the tutorial using functions (the template example can be found here):
fun Application.configureRouting() {
configureArticleRouting()
routing {
get("/") {
val name = "Ktor"
call.respondHtml(HttpStatusCode.OK) {
mainLayout(title = name){
articleContent(Article("Article Title", "My article content"))
}
}
}
}
}
fun FlowContent.articleContent(article: Article) {
article {
h2 {
+article.title
}
p {
+article.content
}
}
}
fun HTML.mainLayout(title: String, content: FlowContent.() -> Unit) {
head {
title {
+title
}
}
body {
content()
}
}
data class Article(val title: String, val content: String)
The question is, what is the advantage of using templates?
Thanks,

Kotlin - extensible type-safe builders

I want to be able to create a custom builder-pattern DSL-type thing, and I want the ability to create new components in a clean and type-safe way. How can I hide the implementation details required for creating and extending such a builder-pattern?
The Kotlin docs give something like the following example:
html {
head {
title {+"XML encoding with Kotlin"}
}
body {
h1 {+"XML encoding with Kotlin"}
p {+"this format can be used as an alternative markup to XML"}
a(href = "http://kotlinlang.org") {+"Kotlin"}
// etc...
}
}
Here, all of the possible "elements" are predefined and implemented as functions that also return objects of the corresponding types. (eg. the html function returns an instance of the HTML class)
Each function is defined so that it adds itself to its parent context's object as a child.
Suppose someone wanted to create a new element type NewElem usable as newelem. They would have to do something cumbersome such as:
class NewElem : Element() {
// ...
}
fun Element.newelem(fn: NewElem.() -> Unit = {}): NewElem {
val e = NewElem()
e.fn()
this.addChild(e)
return e
}
every time.
Is there a clean way to hide this implementation detail?
I want to be able to create a new element by simply extending Element for example.
I do not want to use reflection if possible.
Possibilities I Tried
My main problem is coming up with a clean solution. I thought of a couple other approaches that didn't pan out.
1) Create new elements with a function call that returns a function to be used in the builder style such as:
// Pre-defined
fun createElement(...): (Element.() -> Unit) -> Element
// Created as
val newelem = createElement(...)
// Used as
body {
newelem {
p { +"newelem example" }
}
}
There are obvious downsides to this, and I don't see a clear way to implement it either - probably would involve reflection.
2) Override the invoke operator in companion object
abstract class Element {
companion object {
fun operator invoke(build: Element.() -> Unit): Element {
val e = create()
e.build()
return e
}
abstract fun create(): Element
}
}
// And then you could do
class NewElem : Element() {
companion object {
override fun create(): Element {
return NewElem()
}
}
}
Body {
NewElem {
P { text = "NewElem example" }
}
}
It is unfortunately not possible to enforce "static" functions to be implemented by subclasses in a type-safe way.
Also, companion objects aren't inherited, so the invoke on subclasses wouldn't work anyway.
And we again run into problems about adding children elements to the correct context, so the builder doesn't actually build anything.
3) Override the invoke operator on Element types
abstract class Element {
operator fun invoke(build: Element.() -> Unit): Element {
this.build()
return this
}
}
class NewElem(val color: Int = 0) : Element()
Body() {
NewElem(color = 0xff0000) {
P("NewElem example")
}
}
This might have worked, except for when you immediately try to invoke on the object created by the constructor call, the compiler cannot tell that the lambda is for the "invoke" call and tries to pass it into the constructor.
This can be fixed by making something slightly less clean:
operator fun Element.minus(build: Element.() -> Unit): Element {
this.build()
return this
}
Body() - {
NewElem(color = 0xff0000) - {
P("NewElem example")
}
}
But yet again, adding children elements to the parent elements isn't actually possible without reflection or something similar, so the builder still doesn't actually build anything.
4) Calling add() for sub-elements
To try to fix the issue of the builder not actually building anything, we could implement an add() function for sub-elements.
abstract class Element {
fun add(elem: Element) {
this.children.add(elem)
}
}
Body() - {
add(NewElem(color = 0xff0000) - {
add(P("NewElem red example"))
add(P("NewElem red example 2"))
})
add(NewElem(color = 0x0000ff) - {
add(P("NewElem blue example"))
})
}
But this is obviously not clean and is just deferring the cumbersome-ness to the usage side instead of the implementation side.
I think it's unavoidable to add some sort of a helper function for each Element subclass you create, but their implementation can be simplified with generic helper functions.
For example, you can create a function that performs the setup call and adds the new element to the parent, then you only have to call into this function and create an instance of your new element:
fun <T : Element> Element.nest(elem: T, fn: T.() -> Unit): T {
elem.fn()
this.addChild(elem)
return elem
}
fun Element.newElem(fn: NewElem.() -> Unit = {}): NewElem = nest(NewElem(), fn)
Alternatively, you could create that instance via reflection to simplify even further, but since you've stated you'd like to avoid it, this will probably seem unnecessary:
inline fun <reified T : Element> Element.createAndNest(fn: T.() -> Unit): T {
val elem = T::class.constructors.first().call()
elem.fn()
this.addChild(elem)
return elem
}
fun Element.newElem(fn: NewElem.() -> Unit = {}) = createAndNest(fn)
These still leave you with having to declare a factory function with the appropriate header, but this is the only way to achieve the syntax that the HTML example achieves, where a NewElem can be created with its own newElem function.
I came up with a solution that isn't the most elegant, but it is passable and works the way I would want it to.
It turns out that if you override an operator (or create any extension function for that matter) inside a class, it has access to its parent context.
So I overrode the unary + operator
abstract class Element {
val children: ArrayList<Element> = ArrayList()
// Create lambda to add children
operator fun minus(build: ElementCollector.() -> Unit): Element {
val collector = ElementCollector()
collector.build()
children.addAll(collector.children)
return this
}
}
class ElementCollector {
val children: ArrayList<Element> = ArrayList()
// Add child with unary + prefix
operator fun Element.unaryPlus(): Element {
this#ElementCollector.children.add(this)
return this
}
}
// For consistency
operator fun Element.unaryPlus() = this
This allows me to create new elements and use them like this:
class Body : Element()
class NewElem : Element()
class Text(val t: String) : Element()
fun test() =
+Body() - {
+NewElem()
+NewElem() - {
+Text("text")
+Text("elements test")
+NewElem() - {
+Text("child of child of child")
}
+Text("it works!")
}
+NewElem()
}

How to work with Type-Safe Builders in Kotlin?

I've seen lots of tutorials but still didn't get exactly how it works. I understood the main idea: a function holding functions with data, but looking official documentation I couldn't realize how and where the data is stored and who calls the function responsible for its storaging. Other tutorials seems to show just a snippet of code, which didn't help me much. Can you give me a full and simple example with a trivial class, like a person, please?
I was interested in some details, too. Here's what I wrote:
data class Person(
var name: String? = null,
var age: Int? = null,
val children: MutableList<Person> = ArrayList()
) {
fun child(init: Person.() -> Unit) = Person().also {
it.init()
children.add(it)
}
}
fun person(init: Person.() -> Unit) = Person().apply { init() }
fun main(args: Array<String>) {
val p = person {
name = "Mommy"
age = 33
child {
name = "Gugu"
age = 2
}
child {
name = "Gaga"
age = 3
}
}
println(p)
}
It prints out (with a little formatting added):
Person(name=Mommy, age=33, children=[
Person(name=Gugu, age=2, children=[]),
Person(name=Gaga, age=3, children=[])
])
Kotlin DSLs
Kotlin is great for writing your own Domain Specific Languages, also called type-safe builders. Anko is one of the examples using such DSLs. The most important language feature you need to understand here is called "Function Literals with Receiver", which you made use of already: Test.() -> Unit
Function Literals with Receiver - Basics
Kotlin supports the concept of “function literals with receivers”. This enables us to call methods on the receiver of the function literal in its body without any specific qualifiers. This is very similar to extension functionsin which it’s also possible to access members of the receiver object inside the extension.
A simple example, also one of the greatest functions in the Kotlin standard library, isapply
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
As you can see, such a function literal with receiver is taken as the argument block here. This block is simply executed and the receiver (which is an instance of T) is returned. In action this looks as follows:
val foo: Bar = Bar().apply {
color = RED
text = "Foo"
}
We instantiate an object of Bar and call apply on it. The instance of Bar becomes the “receiver”. The block, passed as an argument in {}(lambda expression) does not need to use additional qualifiers to access and modify the shown visible properties color and text.
Function Literals with Receiver - in DSL
If you look at this example, taken from the documentation, you see this in action:
class HTML {
fun body() { ... }
}
fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // create the receiver object
html.init() // pass the receiver object to the lambda
return html
}
html { // lambda with receiver begins here
body() // calling a method on the receiver object
}
The html() function expects such a function literal with receiver with HTML as the receiver. In the function body you can see how it is used: an instance of HTML is created and the init is called on it.
Benefit
The caller of such an higher-order function expecting a function literal with receiver (like html()) you can use any visible HTML function and property without additional qualifiers (like this e.g.), as you can see in the call:
html { // lambda with receiver begins here
body() // calling a method on the receiver object
}
Example
I've written a sample DSL and described it in a blog post. Maybe that's also helpful.
Just to add other syntaxe
data class QCMBean(var qcmId : Int=-1, var question : String = "", var answers : ArrayList<AnswerBean> = ArrayList()) {
companion object {
fun qcm(init:QCMBean.()->Unit) = QCMBean().apply {
init()
}
}
fun answer(answer:String = "") = AnswerBean(answer).apply {
answers.add(this)
}
}
data class AnswerBean(var answer:String = "")
qcm {
qcmId = 1
question = "How many cat ?"
answer("1")
answer("2")
}

How do I extract parts of code into local variables in Kotlin when using Ktor's HTML builder?

I am trying to understand the HTML builder in Kotlin / Ktor.
The example here uses the HTML builder to build the result:
call.respondHtml {
head {
title { +"HTML Application" }
}
body {
h1 { +"Sample application with HTML builders" }
widget {
+"Widgets are just functions"
}
}
}
I am trying to extract the body into a variable like this:
val block: HTML.() -> Unit = {
head {
title { +"HTML Application" }
}
body {
h1 { +"Sample application with HTML builders" }
}
}
call.respondHtml(block)
Now I get the following compile error:
Error:(37, 22) Kotlin: None of the following functions can be called with the arguments supplied:
public suspend fun ApplicationCall.respondHtml(status: HttpStatusCode = ..., versions: List<Version> = ..., cacheControl: CacheControl? = ..., block: HTML.() -> Unit): Unit defined in org.jetbrains.ktor.html
public suspend fun ApplicationCall.respondHtml(status: HttpStatusCode = ..., block: HTML.() -> Unit): Unit defined in org.jetbrains.ktor.html
When I add the first (optional) argument it works again: call.respondHtml(HttpStatusCode.OK, block).
Why does it not work, when I simply try to extract the body into a variable?
I think the compiler doesn't like having a mandatory after default parameters, unless it is a lambda outside of the braces.
Try to name it:
call.respondHtml(block = block)
BTW, if what you want is to extract logic, I would recommend using functions. For your example:
fun HTML.headAndBody() {
head {
title { +"HTML Application" }
}
body {
h1 { +"Sample application with HTML builders" }
widget {
+"Widgets are just functions"
}
}
}
call.respondHtml {
headAndBody()
}
That way you can even add parameters to your block of html, creating a custom component out of it.

How do I write to a file in Kotlin?

I can't seem to find this question yet, but what is the simplest, most-idiomatic way of opening/creating a file, writing to it, and then closing it? Looking at the kotlin.io reference and the Java documentation I managed to get this:
fun write() {
val writer = PrintWriter("file.txt") // java.io.PrintWriter
for ((member, originalInput) in history) { // history: Map<Member, String>
writer.append("$member, $originalInput\n")
}
writer.close()
}
This works, but I was wondering if there was a "proper" Kotlin way of doing this?
A bit more idiomatic. For PrintWriter, this example:
File("somefile.txt").printWriter().use { out ->
history.forEach {
out.println("${it.key}, ${it.value}")
}
}
The for loop, or forEach depends on your style. No reason to use append(x) since that is basically write(x.toString()) and you already give it a string. And println(x) basically does write(x) after converting a null to "null". And println() does the correct line ending.
If you are using data classes of Kotlin, they can already be output because they have a nice toString() method already.
Also, in this case if you wanted to use BufferedWriter it would produce the same results:
File("somefile.txt").bufferedWriter().use { out ->
history.forEach {
out.write("${it.key}, ${it.value}\n")
}
}
Also you can use out.newLine() instead of \n if you want it to be correct for the current operating system in which it is running. And if you were doing that all the time, you would likely create an extension function:
fun BufferedWriter.writeLn(line: String) {
this.write(line)
this.newLine()
}
And then use that instead:
File("somefile.txt").bufferedWriter().use { out ->
history.forEach {
out.writeLn("${it.key}, ${it.value}")
}
}
And that's how Kotlin rolls. Change things in API's to make them how you want them to be.
Wildly different flavours for this are in another answer: https://stackoverflow.com/a/35462184/3679676
Other fun variations so you can see the power of Kotlin:
A quick version by creating the string to write all at once:
File("somefile.txt").writeText(history.entries.joinToString("\n") { "${it.key}, ${it.value}" })
// or just use the toString() method without transform:
File("somefile.txt").writeText(x.entries.joinToString("\n"))
Or assuming you might do other functional things like filter lines or take only the first 100, etc. You could go this route:
File("somefile.txt").printWriter().use { out ->
history.map { "${it.key}, ${it.value}" }
.filter { ... }
.take(100)
.forEach { out.println(it) }
}
Or given an Iterable, allow writing it to a file using a transform to a string, by creating extension functions (similar to writeText() version above, but streams the content instead of materializing a big string first):
fun <T: Any> Iterable<T>.toFile(output: File, transform: (T)->String = {it.toString()}) {
output.bufferedWriter().use { out ->
this.map(transform).forEach { out.write(it); out.newLine() }
}
}
fun <T: Any> Iterable<T>.toFile(outputFilename: String, transform: (T)->String = {it.toString()}) {
this.toFile(File(outputFilename), transform)
}
used as any of these:
history.entries.toFile(File("somefile.txt")) { "${it.key}, ${it.value}" }
history.entries.toFile("somefile.txt") { "${it.key}, ${it.value}" }
or use default toString() on each item:
history.entries.toFile(File("somefile.txt"))
history.entries.toFile("somefile.txt")
Or given a File, allow filling it from an Iterable, by creating this extension function:
fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) {
this.bufferedWriter().use { out ->
things.map(transform).forEach { out.write(it); out.newLine() }
}
}
with usage of:
File("somefile.txt").fillWith(history.entries) { "${it.key}, ${it.value}" }
or use default toString() on each item:
File("somefile.txt").fillWith(history.entries)
which if you had the other toFile extension already, you could rewrite having one extension call the other:
fun <T: Any> File.fillWith(things: Iterable<T>, transform: (T)->String = {it.toString()}) {
things.toFile(this, transform)
}
It mostly looks ok to me. The only thing different I would do is use the "use" extension defined in ReadWrite to auto close the writer.
PrintWriter("file.txt").use {
for ((member, originalInput) in history) { // history: Map<Member, String>
it.append("$member, $originalInput\n")
}
}
At the very minimum, you could use:
FileWriter(filename).use { it.write(text) }
FileWriter is a convenience class for writing character files (provided by Java, and hence available in Kotlin). It extends Closeable, and hence can be used by Kotlin's ".use" extension method.
The .use extension method automatically closes the calling object once the block exits, thus providing an idiomatic way to close the file after it's written.
Some Kotlin magic allows to omit referencing the stream on each read or write call:
fun <T : Closeable, R> T.useWith(block: T.() -> R): R = use { with(it, block) }
File("a.in").bufferedReader().useWith {
File("a.out").printWriter().useWith {
val (a, b) = readLine()!!.split(' ').map(String::toInt)
println(a + b)
}
}
Scanner(File("b.in")).useWith {
PrintWriter("b.out").useWith {
val a = nextInt()
val b = nextInt()
println(a + b)
}
}
try{
val fileWriter = FileWriter("test.txt", true)
fileWriter.write(string+ "\n")
fileWriter.close()
} catch (exception: Exception){
println(exception.message)
}
Example as easy
val path = context!!.filesDir.absolutePath // => /data/user/0/com.example.test/files
File("$path/filename.txt").writeText("hello")
File(requireContext().filesDir, "TodayTaskListChange.txt").writeText("write your test here...")