SlideShare a Scribd company logo
DSLs IN A
KOTLIN WAY
Ubiratan Soares
July / 2018
VERSION
2.0
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
SELECT *
FROM accounts
WHERE id=12345
SELECT *
FROM accounts
WHERE id=12345
"
"
String sql = SQLiteQueryBuilder
.select("*")
.from("accounts")
.where("id=12345")
.toString();
https://github.com/alexfu/SQLiteQueryBuilder
<!DOCTYPE html>
<html>
<body>
<h1>Hey!!"h1>
<div>Ho!<span>Lets go!!"span>
!"div>
!"body>
!"html>
val tree = createHTMLDocument().html {
body {
h1 { +"Hey" }
div {
+"Ho!" span { +"Lets go!" }
}
}
}
https://github.com/Kotlin/kotlinx.html
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
Disclaimer : Strategic jump
Type Aliases
Sealed Classes
Extension Functions
Extension Properties
ETC
VERSION
1.0
INFIX
NOTATION
class Extractor {
fun firstLetter(target: String) =
target[0].toString()
}
val k = Extractor().firstLetter("Kotlin")
class Extractor {
infix fun firstLetter(target: String) =
target[0].toString()
}
val k = Extractor() firstLetter "Kotlin"
👌
object extract {
infix fun firstLetterOf(target: String)
= target[0].toString()
}
object extract {
infix fun firstLetterOf(target: String)
= target[0].toString()
}
val first = extract firstLetterOf "Awesome"
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
object acronymn {
infix fun from(target: String) = Chainer(
initials = mutableListOf(),
seed = target
)
}
object acronymn {
infix fun from(target: String) = Chainer(
initials = mutableListOf(),
seed = target
)
}
class Chainer(
private val initials: MutableList<String>,
seed: String) {
init {
initials += seed.first().toString()
}
class Chainer(…) {
init {
initials += seed.first().toString()
}
infix fun and(another: String) =
Chainer(initials, another)
class Chainer(…) {
init {
initials += seed.first().toString()
}
infix fun and(another: String) =
Chainer(initials, another)
sealed class Joiner
object noPunctuaction : Joiner()
object dots : Joiner()
class Chainer(…) {
infix fun joinedWith(option: Joiner) =
initials.reduce { previous, letter !"
val next = when (option) {
is noPunctuaction !" letter
is dots !" "$letter."
}
"$previous$next"
}
class Chainer(…) {
infix fun joinedWith(option: Joiner) =
initials.reduce { previous, letter !"
val next = when (option) {
is noPunctuaction !" letter
is dots !" "$letter."
}
"$previous$next"
}
class Chainer(…) {
infix fun joinedWith(option: Joiner) =
initials.reduce { previous, letter !"
val next = when (option) {
is noPunctuaction !" letter
is dots !" "$letter."
}
"$previous$next"
}
class Chainer(…) {
infix fun joinedWith(option: Joiner) =
initials.reduce { previous, letter !"
val next = when (option) {
is noPunctuaction !" letter
is dots !" "$letter."
}
"$previous$next"
}
val dsl = acronymn from
"Domain" and
"Specific" and
"Language" joinedWith
noPunctuaction //DSL
val dsl = acronymn from
"Domain" and
"Specific" and
"Language" joinedWith
dots //D.S.L
OPERATOR
OVERLOADS
val items = mutableListOf(1, 2, 3)
items += 4
val items = mutableListOf(1, 2, 3)
items += 4
/#$
* Adds the specified [element] to this mutable collection.
%&
@kotlin.internal.InlineOnly
public inline operator fun <T> MutableCollection<in T>.plusAssign(element: T) {
this.add(element)
}
typealias IntPair = Pair<Int, Int>
val calendar by lazy {
Calendar.getInstance()
}
operator fun Date.plus(args: IntPair): Date {
calendar.time = this
calendar.add(args.first, args.second)
return calendar.time
}
operator fun Date.minus(args: IntPair): Date {
calendar.time = this
calendar.add(args.first, -args.second)
return calendar.time
}
operator fun Date.plus(args: IntPair): Date {
calendar.time = this
calendar.add(args.first, args.second)
return calendar.time
}
operator fun Date.minus(args: IntPair): Date {
calendar.time = this
calendar.add(args.first, -args.second)
return calendar.time
}
fun Int.days() =
Calendar.DAY_OF_YEAR to this
fun Int.months() =
Calendar.MONTH to this
val atPast = Date() - 2.months()
val atFuture = Date() + 15.days()
val past = Date() - 2.months
val future = Date() + 15.days
👌
val Int.days: IntPair
get() = Calendar.DAY_OF_YEAR to this
val Int.months: IntPair
get() = Calendar.MONTH to this
A The problem
like with spannables
on Android
val toSpan = SpannableStringBuilder()
val start = toSpan.length
toSpan.append("First Part")
toSpan.setSpan(
UnderlineSpan(),
start,
toSpan.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
toSpan.setSpan(
StyleSpan(android.graphics.Typeface.BOLD),
start,
toSpan.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
toSpan.append("not bold or underlined")
operator fun SpannableString.plus(s: String) =
SpannableString(TextUtils.concat(this, s))
operator fun SpannableString.plus(s: SpannableString) =
SpannableString(TextUtils.concat(this, s))
fun span(given: CharSequence, span: Any): SpannableString {
val spannable =
if (given is String) SpannableString(given)
else given as? SpannableString ?: throw CannotBeSpanned
return spannable.apply {
setSpan(span, 0, length, SPAN_EXCLUSIVE_EXCLUSIVE)
}
}
object CannotBeSpanned : IllegalArgumentException(
"Cannot apply span. Should be String or SpannableString"
)
// Add more hooks to same span() function
fun italic(given: CharSequence) =
span(given, StyleSpan(Typeface.ITALIC))
fun underline(given: CharSequence) =
span(given, UnderlineSpan())
fun bold(given: CharSequence) =
span(given, StyleSpan(Typeface.BOLD))
val spanned =
"normal" +
bold("bold") +
italic("italic")
label.setText(spanned)
LAMBDAS +
RECEIVERS
fun x(lambda: () !" Unit) { lambda() }
fun y(lambda: () !" Int) = lambda()
val x: () !" Int = { TODO() }
val result = x()
val add = fun(a: Int, b: Int) = a + b
fun calculate(func: (Int, Int) !" Int) {
func.invoke(2,2)
}
// Trailling Notation
calculate { a, b !" a + b }
// Normal notation
calculate(add)
class Receiver(val data: Int)
// Kotlin allows us to add an extension function
// literal to a type. Such lambda acquires the
// properties of non-static method in the context
val addOne: Receiver.() !" Int = {
data + 1
}
val two = addOne(Receiver(1))
val twoAgain = Receiver(1).addOne()
fun receive(block: Receiver.() !" Unit) {
val r = Receiver(data = 1)
block(r)
// r.block() is exactly the same
}
receive {
println(data) // 1
}
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
https://graphql.org/swapi-graphql/
val starWars = query {
allFilms {
film { title director }
}
}
println(starWars)
> query { allFilms { film { title director } } }
val starWars = query {
'( TODO
}
val starWars = query {
'( TODO
}
fun query(): String {
return "query { ${ '( Something here } }"
}
val starWars = query {
'( TODO
}
fun query(setup: AllFilmsBlock.() !" String) =
"query { ${setup(AllFilmsBlock())} }"
val starWars = query {
'( TODO
}
fun query(setup: AllFilmsBlock.() !" String) =
"query { ${setup(AllFilmsBlock())} }"
val starWars = query {
'( TODO
}
fun query(setup: AllFilmsBlock.() !" String) =
"query { ${setup(AllFilmsBlock())} }"
fun query(setup: AllFilmsBlock.() !" String) =
"query { ${setup(AllFilmsBlock())} }"
val starWars = query {
allFilms { // TODO }
}
class AllFilmsBlock {
fun allFilms(setup: FilmBlock.() !" String) =
"allFilms { ${setup(FilmBlock())} }"
}
fun query(setup: AllFilmsBlock.() !" String) =
"query { ${setup(AllFilmsBlock())} }"
val starWars = query {
allFilms { // TODO }
}
class AllFilmsBlock {
fun allFilms(setup: FilmBlock.() !" String) =
"allFilms { ${setup(FilmBlock())} }"
}
val starWars = query {
allFilms {
film {
// TODO
}
}
}
val starWars = query {
allFilms { film { } }
}
class FilmBlock {
fun film(setup: FilmFields.() !" String) =
with(FilmFields()) {
setup()
"film { ${fields()} }"
}
}
val starWars = query {
allFilms { film { } }
}
class FilmBlock {
fun film(setup: FilmFields.() !" String) =
with(FilmFields()) {
setup()
"film { ${fields()} }"
}
}
val starWars = query {
allFilms { film { } }
}
class FilmBlock {
fun film(setup: FilmFields.() !" String) =
with(FilmFields()) {
setup()
"film { ${fields()} }"
}
}
class FilmFiels {
private val picked = mutableListOf<String>()
fun fields() = TODO()
val title: String
get() {
picked.add(TITLE)
return TITLE
}
}
class FilmFields {
val title: String
get() { … }
val director: String
get() { … }
private companion object {
const val TITLE = "title"
const val DIRECTOR = "director"
}
}
class FilmFields {
fun fields() =
picked.distinct().joinToString(separator = " ")
val title: String
get() { … }
val director: String
get() { … }
private companion object { … }
}
class FilmFields {
fun fields() =
picked.distinct().joinToString(separator = " ")
val title: String
get() { … }
val director: String
get() { … }
private companion object { … }
}
val starWars = query {
allFilms {
film {
title
director
}
}
}
println(starWars)
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
// Plain old mockWebServer
val server = MockWebServer()
val response = MockResponse().apply {
setResponseCode(503)
setBody("Ops!")
}
server.enqueue(response)
server.start()
class MockResponseBuilder(
'( Aliases
var code: Int = 0,
var response: String? = null) {
fun mockResponse() = MockResponse().apply {
setResponseCode(code)
setBody(response)
}
}
class QueueBuilder {
val mocks = mutableListOf<MockResponse>()
fun enqueueMock(setup: MockResponseBuilder.() !" Unit) {
val builder = MockResponseBuilder()
builder.setup()
mocks.add(builder.mockResponse())
}
}
typealias BuildMock = MockResponseBuilder.() !" Unit
class QueueBuilder {
val mocks = mutableListOf<MockResponse>()
fun enqueueMock(setup: BuildMock) =
MockResponseBuilder().run {
setup()
mocks.add(mockResponse())
}
}
typealias BuildMock = MockResponseBuilder.() !" Unit
class QueueBuilder {
val mocks = mutableListOf<MockResponse>()
fun enqueueMock(setup: BuildMock) =
MockResponseBuilder().run {
setup()
mocks.add(mockResponse())
}
}
typealias BuildQueue = QueueBuilder.() !" Unit
fun newServer(setup: BuildQueue): MockWebServer =
with(MockWebServer()) {
'( ????
return this
}
typealias BuildQueue = QueueBuilder.() !" Unit
fun newServer(setup: BuildQueue): MockWebServer =
with(MockWebServer()) {
QueueBuilder().run {
setup()
mocks.forEach { enqueue(it) }
}
return this
}
typealias BuildQueue = QueueBuilder.() !" Unit
fun newServer(setup: BuildQueue): MockWebServer =
with(MockWebServer()) {
QueueBuilder().run {
setup()
mocks.forEach { enqueue(it) }
}
return this
}
// DSL based
val server = newServer {
enqueueMock {
code = 200
response = "OK"
}
}
server.start()
// Plain old mockWebServer
val server = MockWebServer()
val response = MockResponse().apply {
setResponseCode(503)
setBody("Ops!")
}
server.enqueue(response)
server.start()
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
FINAL

REMARKS
CONCLUSIONS
• DSLs are fun (with no pun)
• DSL-building offer great insights over Kotlin features!
• DSLs should work to improve an existing domain, not replace it
• Design your own DSLs for fun and profit !
https://speakerdeck.com/ubiratansoares
UBIRATAN
SOARES
Computer Scientist by ICMC/USP
Software Engineer, curious guy
Google Expert for Android and Kotlin
Teacher, speaker, etc, etc
THANK YOU
@ubiratanfsoares
ubiratansoares.github.io
https://br.linkedin.com/in/ubiratanfsoares

More Related Content

PDF
Functional programming basics
PDF
JDD 2016 - Pawel Byszewski - Kotlin, why?
PDF
Exploring ZIO Prelude: The game changer for typeclasses in Scala
PDF
Sneaking inside Kotlin features
PPTX
Kotlin collections
PDF
Hammurabi
PPTX
Poor Man's Functional Programming
PDF
Feel of Kotlin (Berlin JUG 16 Apr 2015)
Functional programming basics
JDD 2016 - Pawel Byszewski - Kotlin, why?
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Sneaking inside Kotlin features
Kotlin collections
Hammurabi
Poor Man's Functional Programming
Feel of Kotlin (Berlin JUG 16 Apr 2015)

What's hot (20)

PDF
Scalaz 8 vs Akka Actors
PDF
Refactoring to Macros with Clojure
KEY
関数潮流(Function Tendency)
PDF
Nik Graf - Get started with Reason and ReasonReact
PDF
Pragmatic Real-World Scala (short version)
KEY
Google Guava
PPTX
Basic java, java collection Framework and Date Time API
PDF
Google Guava - Core libraries for Java & Android
PDF
Hive function-cheat-sheet
ODP
WorkingWithSlick2.1.0
PDF
From java to kotlin beyond alt+shift+cmd+k
PPTX
Benefits of Kotlin
PDF
Kotlin, why?
PDF
The Ring programming language version 1.5.1 book - Part 43 of 180
PDF
Functional Scala 2020
PDF
"Kotlin и rx в android" Дмитрий Воронин (Avito)
PDF
Kotlin Advanced - Apalon Kotlin Sprint Part 3
PDF
Functional Programming for OO Programmers (part 2)
PDF
Google Guava for cleaner code
PDF
JavaScript ∩ WebAssembly
Scalaz 8 vs Akka Actors
Refactoring to Macros with Clojure
関数潮流(Function Tendency)
Nik Graf - Get started with Reason and ReasonReact
Pragmatic Real-World Scala (short version)
Google Guava
Basic java, java collection Framework and Date Time API
Google Guava - Core libraries for Java & Android
Hive function-cheat-sheet
WorkingWithSlick2.1.0
From java to kotlin beyond alt+shift+cmd+k
Benefits of Kotlin
Kotlin, why?
The Ring programming language version 1.5.1 book - Part 43 of 180
Functional Scala 2020
"Kotlin и rx в android" Дмитрий Воронин (Avito)
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Functional Programming for OO Programmers (part 2)
Google Guava for cleaner code
JavaScript ∩ WebAssembly
Ad

Similar to TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way (20)

PDF
つくってあそぼ Kotlin DSL ~拡張編~
PDF
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
PDF
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
PPT
SDC - Einführung in Scala
PDF
2014-11-01 01 Денис Нелюбин. О сортах кофе
PDF
Swift 함수 커링 사용하기
PPTX
EcmaScript unchained
ODP
Scala 2 + 2 > 4
PDF
Kotlin : Advanced Tricks - Ubiratan Soares
PDF
Persisting Data on SQLite using Room
PDF
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
PDF
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
PDF
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
PDF
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
PDF
6. Generics. Collections. Streams
PPTX
K is for Kotlin
PDF
Hitchhiker's Guide to Functional Programming
PDF
Miracle of std lib
PPT
OBJECTS IN Object Oriented Programming .ppt
PDF
Kotlin Generation
つくってあそぼ Kotlin DSL ~拡張編~
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
SDC - Einführung in Scala
2014-11-01 01 Денис Нелюбин. О сортах кофе
Swift 함수 커링 사용하기
EcmaScript unchained
Scala 2 + 2 > 4
Kotlin : Advanced Tricks - Ubiratan Soares
Persisting Data on SQLite using Room
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
6. Generics. Collections. Streams
K is for Kotlin
Hitchhiker's Guide to Functional Programming
Miracle of std lib
OBJECTS IN Object Oriented Programming .ppt
Kotlin Generation
Ad

More from tdc-globalcode (20)

PDF
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
PDF
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
PDF
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
PDF
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
PDF
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
PDF
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
PDF
TDC2019 Intel Software Day - Inferencia de IA em edge devices
PDF
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
PPT
Trilha .Net - Programacao funcional usando f#
PDF
TDC2018SP | Trilha Go - Case Easylocus
PDF
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
PDF
TDC2018SP | Trilha Go - Clean architecture em Golang
PDF
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
PDF
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
PDF
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
PDF
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
PDF
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
PDF
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
PDF
TDC2018SP | Trilha .Net - .NET funcional com F#
PDF
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core
TDC2019 Intel Software Day - Visao Computacional e IA a servico da humanidade
TDC2019 Intel Software Day - Tecnicas de Programacao Paralela em Machine Lear...
TDC2019 Intel Software Day - ACATE - Cases de Sucesso
TDC2019 Intel Software Day - Otimizacao grafica com o Intel GPA
TDC2019 Intel Software Day - Deteccao de objetos em tempo real com OpenVino
TDC2019 Intel Software Day - OpenCV: Inteligencia artificial e Visao Computac...
TDC2019 Intel Software Day - Inferencia de IA em edge devices
Trilha BigData - Banco de Dados Orientado a Grafos na Seguranca Publica
Trilha .Net - Programacao funcional usando f#
TDC2018SP | Trilha Go - Case Easylocus
TDC2018SP | Trilha Modern Web - Para onde caminha a Web?
TDC2018SP | Trilha Go - Clean architecture em Golang
TDC2018SP | Trilha Go - "Go" tambem e linguagem de QA
TDC2018SP | Trilha Mobile - Digital Wallets - Seguranca, inovacao e tendencia
TDC2018SP | Trilha .Net - Real Time apps com Azure SignalR Service
TDC2018SP | Trilha .Net - Passado, Presente e Futuro do .NET
TDC2018SP | Trilha .Net - Novidades do C# 7 e 8
TDC2018SP | Trilha .Net - Obtendo metricas com TDD utilizando build automatiz...
TDC2018SP | Trilha .Net - .NET funcional com F#
TDC2018SP | Trilha .Net - Crie SPAs com Razor e C# usando Blazor em .Net Core

Recently uploaded (20)

PDF
Abdominal Access Techniques with Prof. Dr. R K Mishra
PPTX
1st Inaugural Professorial Lecture held on 19th February 2020 (Governance and...
PDF
01-Introduction-to-Information-Management.pdf
PDF
TR - Agricultural Crops Production NC III.pdf
PDF
Insiders guide to clinical Medicine.pdf
PDF
2.FourierTransform-ShortQuestionswithAnswers.pdf
PPTX
human mycosis Human fungal infections are called human mycosis..pptx
PPTX
Microbial diseases, their pathogenesis and prophylaxis
PPTX
Institutional Correction lecture only . . .
PDF
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PPTX
school management -TNTEU- B.Ed., Semester II Unit 1.pptx
PPTX
Renaissance Architecture: A Journey from Faith to Humanism
PDF
Anesthesia in Laparoscopic Surgery in India
PPTX
Final Presentation General Medicine 03-08-2024.pptx
PDF
Computing-Curriculum for Schools in Ghana
PDF
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
PDF
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PDF
Pre independence Education in Inndia.pdf
PPTX
PPT- ENG7_QUARTER1_LESSON1_WEEK1. IMAGERY -DESCRIPTIONS pptx.pptx
Abdominal Access Techniques with Prof. Dr. R K Mishra
1st Inaugural Professorial Lecture held on 19th February 2020 (Governance and...
01-Introduction-to-Information-Management.pdf
TR - Agricultural Crops Production NC III.pdf
Insiders guide to clinical Medicine.pdf
2.FourierTransform-ShortQuestionswithAnswers.pdf
human mycosis Human fungal infections are called human mycosis..pptx
Microbial diseases, their pathogenesis and prophylaxis
Institutional Correction lecture only . . .
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
school management -TNTEU- B.Ed., Semester II Unit 1.pptx
Renaissance Architecture: A Journey from Faith to Humanism
Anesthesia in Laparoscopic Surgery in India
Final Presentation General Medicine 03-08-2024.pptx
Computing-Curriculum for Schools in Ghana
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
Black Hat USA 2025 - Micro ICS Summit - ICS/OT Threat Landscape
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
Pre independence Education in Inndia.pdf
PPT- ENG7_QUARTER1_LESSON1_WEEK1. IMAGERY -DESCRIPTIONS pptx.pptx

TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way

  • 1. DSLs IN A KOTLIN WAY Ubiratan Soares July / 2018 VERSION 2.0
  • 5. String sql = SQLiteQueryBuilder .select("*") .from("accounts") .where("id=12345") .toString(); https://github.com/alexfu/SQLiteQueryBuilder
  • 7. val tree = createHTMLDocument().html { body { h1 { +"Hey" } div { +"Ho!" span { +"Lets go!" } } } } https://github.com/Kotlin/kotlinx.html
  • 12. Type Aliases Sealed Classes Extension Functions Extension Properties ETC
  • 15. class Extractor { fun firstLetter(target: String) = target[0].toString() } val k = Extractor().firstLetter("Kotlin")
  • 16. class Extractor { infix fun firstLetter(target: String) = target[0].toString() } val k = Extractor() firstLetter "Kotlin" 👌
  • 17. object extract { infix fun firstLetterOf(target: String) = target[0].toString() }
  • 18. object extract { infix fun firstLetterOf(target: String) = target[0].toString() } val first = extract firstLetterOf "Awesome"
  • 20. object acronymn { infix fun from(target: String) = Chainer( initials = mutableListOf(), seed = target ) }
  • 21. object acronymn { infix fun from(target: String) = Chainer( initials = mutableListOf(), seed = target ) }
  • 22. class Chainer( private val initials: MutableList<String>, seed: String) { init { initials += seed.first().toString() }
  • 23. class Chainer(…) { init { initials += seed.first().toString() } infix fun and(another: String) = Chainer(initials, another)
  • 24. class Chainer(…) { init { initials += seed.first().toString() } infix fun and(another: String) = Chainer(initials, another)
  • 25. sealed class Joiner object noPunctuaction : Joiner() object dots : Joiner()
  • 26. class Chainer(…) { infix fun joinedWith(option: Joiner) = initials.reduce { previous, letter !" val next = when (option) { is noPunctuaction !" letter is dots !" "$letter." } "$previous$next" }
  • 27. class Chainer(…) { infix fun joinedWith(option: Joiner) = initials.reduce { previous, letter !" val next = when (option) { is noPunctuaction !" letter is dots !" "$letter." } "$previous$next" }
  • 28. class Chainer(…) { infix fun joinedWith(option: Joiner) = initials.reduce { previous, letter !" val next = when (option) { is noPunctuaction !" letter is dots !" "$letter." } "$previous$next" }
  • 29. class Chainer(…) { infix fun joinedWith(option: Joiner) = initials.reduce { previous, letter !" val next = when (option) { is noPunctuaction !" letter is dots !" "$letter." } "$previous$next" }
  • 30. val dsl = acronymn from "Domain" and "Specific" and "Language" joinedWith noPunctuaction //DSL
  • 31. val dsl = acronymn from "Domain" and "Specific" and "Language" joinedWith dots //D.S.L
  • 33. val items = mutableListOf(1, 2, 3) items += 4
  • 34. val items = mutableListOf(1, 2, 3) items += 4 /#$ * Adds the specified [element] to this mutable collection. %& @kotlin.internal.InlineOnly public inline operator fun <T> MutableCollection<in T>.plusAssign(element: T) { this.add(element) }
  • 35. typealias IntPair = Pair<Int, Int> val calendar by lazy { Calendar.getInstance() }
  • 36. operator fun Date.plus(args: IntPair): Date { calendar.time = this calendar.add(args.first, args.second) return calendar.time } operator fun Date.minus(args: IntPair): Date { calendar.time = this calendar.add(args.first, -args.second) return calendar.time }
  • 37. operator fun Date.plus(args: IntPair): Date { calendar.time = this calendar.add(args.first, args.second) return calendar.time } operator fun Date.minus(args: IntPair): Date { calendar.time = this calendar.add(args.first, -args.second) return calendar.time }
  • 38. fun Int.days() = Calendar.DAY_OF_YEAR to this fun Int.months() = Calendar.MONTH to this val atPast = Date() - 2.months() val atFuture = Date() + 15.days()
  • 39. val past = Date() - 2.months val future = Date() + 15.days 👌 val Int.days: IntPair get() = Calendar.DAY_OF_YEAR to this val Int.months: IntPair get() = Calendar.MONTH to this
  • 40. A The problem like with spannables on Android
  • 41. val toSpan = SpannableStringBuilder() val start = toSpan.length toSpan.append("First Part") toSpan.setSpan( UnderlineSpan(), start, toSpan.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) toSpan.setSpan( StyleSpan(android.graphics.Typeface.BOLD), start, toSpan.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ) toSpan.append("not bold or underlined")
  • 42. operator fun SpannableString.plus(s: String) = SpannableString(TextUtils.concat(this, s)) operator fun SpannableString.plus(s: SpannableString) = SpannableString(TextUtils.concat(this, s))
  • 43. fun span(given: CharSequence, span: Any): SpannableString { val spannable = if (given is String) SpannableString(given) else given as? SpannableString ?: throw CannotBeSpanned return spannable.apply { setSpan(span, 0, length, SPAN_EXCLUSIVE_EXCLUSIVE) } } object CannotBeSpanned : IllegalArgumentException( "Cannot apply span. Should be String or SpannableString" )
  • 44. // Add more hooks to same span() function fun italic(given: CharSequence) = span(given, StyleSpan(Typeface.ITALIC)) fun underline(given: CharSequence) = span(given, UnderlineSpan()) fun bold(given: CharSequence) = span(given, StyleSpan(Typeface.BOLD))
  • 45. val spanned = "normal" + bold("bold") + italic("italic") label.setText(spanned)
  • 47. fun x(lambda: () !" Unit) { lambda() } fun y(lambda: () !" Int) = lambda() val x: () !" Int = { TODO() } val result = x()
  • 48. val add = fun(a: Int, b: Int) = a + b fun calculate(func: (Int, Int) !" Int) { func.invoke(2,2) } // Trailling Notation calculate { a, b !" a + b } // Normal notation calculate(add)
  • 49. class Receiver(val data: Int) // Kotlin allows us to add an extension function // literal to a type. Such lambda acquires the // properties of non-static method in the context val addOne: Receiver.() !" Int = { data + 1 } val two = addOne(Receiver(1)) val twoAgain = Receiver(1).addOne()
  • 50. fun receive(block: Receiver.() !" Unit) { val r = Receiver(data = 1) block(r) // r.block() is exactly the same } receive { println(data) // 1 }
  • 53. val starWars = query { allFilms { film { title director } } } println(starWars) > query { allFilms { film { title director } } }
  • 54. val starWars = query { '( TODO }
  • 55. val starWars = query { '( TODO } fun query(): String { return "query { ${ '( Something here } }" }
  • 56. val starWars = query { '( TODO } fun query(setup: AllFilmsBlock.() !" String) = "query { ${setup(AllFilmsBlock())} }"
  • 57. val starWars = query { '( TODO } fun query(setup: AllFilmsBlock.() !" String) = "query { ${setup(AllFilmsBlock())} }"
  • 58. val starWars = query { '( TODO } fun query(setup: AllFilmsBlock.() !" String) = "query { ${setup(AllFilmsBlock())} }"
  • 59. fun query(setup: AllFilmsBlock.() !" String) = "query { ${setup(AllFilmsBlock())} }" val starWars = query { allFilms { // TODO } } class AllFilmsBlock { fun allFilms(setup: FilmBlock.() !" String) = "allFilms { ${setup(FilmBlock())} }" }
  • 60. fun query(setup: AllFilmsBlock.() !" String) = "query { ${setup(AllFilmsBlock())} }" val starWars = query { allFilms { // TODO } } class AllFilmsBlock { fun allFilms(setup: FilmBlock.() !" String) = "allFilms { ${setup(FilmBlock())} }" }
  • 61. val starWars = query { allFilms { film { // TODO } } }
  • 62. val starWars = query { allFilms { film { } } } class FilmBlock { fun film(setup: FilmFields.() !" String) = with(FilmFields()) { setup() "film { ${fields()} }" } }
  • 63. val starWars = query { allFilms { film { } } } class FilmBlock { fun film(setup: FilmFields.() !" String) = with(FilmFields()) { setup() "film { ${fields()} }" } }
  • 64. val starWars = query { allFilms { film { } } } class FilmBlock { fun film(setup: FilmFields.() !" String) = with(FilmFields()) { setup() "film { ${fields()} }" } }
  • 65. class FilmFiels { private val picked = mutableListOf<String>() fun fields() = TODO() val title: String get() { picked.add(TITLE) return TITLE } }
  • 66. class FilmFields { val title: String get() { … } val director: String get() { … } private companion object { const val TITLE = "title" const val DIRECTOR = "director" } }
  • 67. class FilmFields { fun fields() = picked.distinct().joinToString(separator = " ") val title: String get() { … } val director: String get() { … } private companion object { … } }
  • 68. class FilmFields { fun fields() = picked.distinct().joinToString(separator = " ") val title: String get() { … } val director: String get() { … } private companion object { … } }
  • 69. val starWars = query { allFilms { film { title director } } } println(starWars)
  • 71. // Plain old mockWebServer val server = MockWebServer() val response = MockResponse().apply { setResponseCode(503) setBody("Ops!") } server.enqueue(response) server.start()
  • 72. class MockResponseBuilder( '( Aliases var code: Int = 0, var response: String? = null) { fun mockResponse() = MockResponse().apply { setResponseCode(code) setBody(response) } }
  • 73. class QueueBuilder { val mocks = mutableListOf<MockResponse>() fun enqueueMock(setup: MockResponseBuilder.() !" Unit) { val builder = MockResponseBuilder() builder.setup() mocks.add(builder.mockResponse()) } }
  • 74. typealias BuildMock = MockResponseBuilder.() !" Unit class QueueBuilder { val mocks = mutableListOf<MockResponse>() fun enqueueMock(setup: BuildMock) = MockResponseBuilder().run { setup() mocks.add(mockResponse()) } }
  • 75. typealias BuildMock = MockResponseBuilder.() !" Unit class QueueBuilder { val mocks = mutableListOf<MockResponse>() fun enqueueMock(setup: BuildMock) = MockResponseBuilder().run { setup() mocks.add(mockResponse()) } }
  • 76. typealias BuildQueue = QueueBuilder.() !" Unit fun newServer(setup: BuildQueue): MockWebServer = with(MockWebServer()) { '( ???? return this }
  • 77. typealias BuildQueue = QueueBuilder.() !" Unit fun newServer(setup: BuildQueue): MockWebServer = with(MockWebServer()) { QueueBuilder().run { setup() mocks.forEach { enqueue(it) } } return this }
  • 78. typealias BuildQueue = QueueBuilder.() !" Unit fun newServer(setup: BuildQueue): MockWebServer = with(MockWebServer()) { QueueBuilder().run { setup() mocks.forEach { enqueue(it) } } return this }
  • 79. // DSL based val server = newServer { enqueueMock { code = 200 response = "OK" } } server.start() // Plain old mockWebServer val server = MockWebServer() val response = MockResponse().apply { setResponseCode(503) setBody("Ops!") } server.enqueue(response) server.start()
  • 82. CONCLUSIONS • DSLs are fun (with no pun) • DSL-building offer great insights over Kotlin features! • DSLs should work to improve an existing domain, not replace it • Design your own DSLs for fun and profit !
  • 84. UBIRATAN SOARES Computer Scientist by ICMC/USP Software Engineer, curious guy Google Expert for Android and Kotlin Teacher, speaker, etc, etc