DEV Community

Ahmed Rizwan
Ahmed Rizwan

Posted on

8 2

Quick Recipe for creating DSLs in Kotlin

A pretty cool feature in Kotlin is the ability to construct custom DSLs. And you need just four things in order to write them.

  • Infix Notations
  • Extension Methods
  • Lambdas
  • Lambda with Receiver

Let’s go through these one by one.

Infix Notation

Remove brackets & dots!

class Car {
   fun drive(miles: Int) {
      ...
   }
}
val car = Car()
car.drive(10) // normal stuff
Enter fullscreen mode Exit fullscreen mode

Just add infix notation before method declaration for it to work

class Car {
   infix fun drive(miles: Int) {
      ...
   }
}
val car = Car()
car drive 10 // no brackets! no dots!
Enter fullscreen mode Exit fullscreen mode

Extension Methods

Add new functions to any class without having to inherit!

val name = "Ahmed Riz"
name.shout() // won't compile as shout() is not part of String class
Enter fullscreen mode Exit fullscreen mode

In order to make it a part of String class (without inheriting), create shout method prefixed with “String.”

fun String.shout() {
   println("$this !") // this refers to the value of string itself
}
val name = "Ahmed Riz"
name.shout()  // works! and prints out: Ahmed Riz !
Enter fullscreen mode Exit fullscreen mode

Extension methods are project-scoped — you can access them anywhere inside the project.

Lambdas

Pass anonymous function literals (to higher order functions)!

// a higher order function
fun process(value: Int, operation: (Int) -> Unit) {
    operation(value)
}
// when calling, we can pass in a lambda expression
process(10, { value -> println(value) })
// and because it's the last param, we can extract it out
// just to clean things up even further 
process(10) { value -> println(value) } 
Enter fullscreen mode Exit fullscreen mode

Lambda with Receiver

Pass anonymous function literals (to higher order functions), but with a receiver type!

// slight change to the previous higher order function
// now instead of operation: (Int) -> Unit
// we'll do operation: Int.() -> Unit
// This makes Int the receiver type
fun process(value: Int, operation: Int.() -> Unit) {
    value.operation()
}
// usage now becomes
process(10) { println(this) } // prints out: 10
Enter fullscreen mode Exit fullscreen mode

Combining These!

Captain Planet

Let’s now create a DSL of our own. Just to demonstrate:

val myProfile = "Ahmed Rizwan" profile {
    age = 90
    phone = "123 456 789"      
}
Enter fullscreen mode Exit fullscreen mode

Code in order to make it a valid DSL is as simple as this

class Profile(
    val name: String,
    var age: Int? = null,
    var phone: String? = null
)

infix fun String.profile(create: Profile.() -> Unit): Profile {
    val profile = Profile(this)
    profile.create()
    return profile
}
Enter fullscreen mode Exit fullscreen mode

And that’s it!

Although the DSL above might not be a very useful one in real world — but hopefully it gives you an idea of how we can utilize these different Kotlin features to create some custom DSLs of our own.

Happy coding!

Heroku

Amplify your impact where it matters most — building exceptional apps.

Leave the infrastructure headaches to us, while you focus on pushing boundaries, realizing your vision, and making a lasting impression on your users.

Get Started

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

👥 Ideal for solo developers, teams, and cross-company projects

Learn more

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay