{ return this == "Shankha" } fun String?.isNullOrEmpty(): Boolean { return this == null || this.isEmpty() } … if ("Dan".isCool()) print("Dan is cool") public class StringUtils { public static boolean isCool(String receiver) { return receiver.equals("Shankha"); } } … if(StringUtils.isCool("Dan")) System.out.print("Dan is cool");
to build objects • Imperative, not declarative • Can use Kotlin DSLs to build nested object structures • Declarative • Enforcing the hierarchy at compile time, cannot do the wrong thing • Example – HTML builder 10
Kotlin"} } body { p {+"this format can be used as an alternative markup to XML"} a(href = "http://kotlinlang.org") {+"Kotlin"} p { +"Paragraph with some linked" a(href = "http://kotlinlang.org") {+"Kotlin"} +"text" } p { for (person in people) +person.name } } } DSL for HTML
) .body( new Body.Builder() .paragraph( new Paragraph.Builder() .text("this format can be used as an alternative markup to XML") .build() ) .link("http://kotlinlang.org", "Kotlin") .paragraph( new Paragraph.Builder() .text("Paragraph with some linked") .link("http://kotlinlang.org", "Kotlin") .text("text") .build() ) .paragraph(new Paragraph.Builder() .modify( paragraphBuilder -> { for (person: people) { paragraphBuilder.text(person.getName()) } }) .build() ) .build() ) .build(); The Noisy Java Alternative
Kotlin"} body { } } body { head { } p {+"this format can be used as an alternative markup to XML"} // content generated by p { for (person in people) +person.name } } } Incorrect HTML does not compile
render(builder: StringBuilder, indent: String) } class TextElement(val text: String) : Element { override fun render(builder: StringBuilder, indent: String) { … } } abstract class Tag(val name: String) : Element { val children = arrayListOf<Element>() val attributes = hashMapOf<String, String>() protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T { tag.init() children.add(tag) return tag } } 14 How did we achieve such greatness?
String.unaryPlus() { children.add(TextElement(this)) } } class HTML : TagWithText("html") { fun head(init: Head.() -> Unit) = initTag(Head(), init) fun body(init: Body.() -> Unit) = initTag(Body(), init) } class Head : TagWithText("head") { fun title(init: Title.() -> Unit) = initTag(Title(), init) } class Title : TagWithText("title") 15 Create class for each tag
P.() -> Unit) = initTag(P(), init) fun a(href: String, init: A.() -> Unit) { val a = initTag(A(), init) a.href = href } } class Body : BodyTag("body") class P : BodyTag("p") class A : BodyTag("a") { var href: String get() = attributes["href"] set(value) { attributes["href"] = value } } 16 Create class for each tag
aren’t comprehensive • Can we enforce correct use of patterns? • Guarantee thread safety at compile time: • Must hold balance lock when accessing balance • Must hold address lock when accessing the address • Must acquire locks in the same order to prevent deadlocks • When holding both locks, address lock must be acquired last • When acquiring address lock first, the balance lock cannot be acquired 19
addressContext: BankAccountAddress) { var balanceInPennies = 0L fun withAddressLock(body: BankAccountAddress.() -> Unit) { addressLock.withLock { addressContext.body() } } } @BankDSL class BankAccountAddress(var streetNumber: Int, var streetName: String, var cityName: String) { fun sendSecurityNotification(amount: Long) { // Send receipt to address for a large withdrawals } } Implement Individual Contexts
a type-safe way using autocomplete • Ktor • High performance web application framework utilizing Kotlin coroutines • Anko • Android application development • TornadoFX • Build Java FX applications with ease 26