Kotlin DSL: Builder pattern by delegation pt. 1

Let's create a fluent and painless DSL

Davide Giuseppe Farella
3 min readApr 21, 2019

Link to part #2

Introduction

I'm Davide Giuseppe Farella, a freelance Android developer from Italy and a Kotlin lover ❤️

This is my very first story on Medium, hope you will like it.

Builder pattern: why?

Builder pattern is a very common pattern for create a configurable abstraction layer on some APIs: it allow us ( or our user, in case of a library ) to define an infinite number of parameters, without declare an equal infinite number of methods; well, Kotlin came to help us with default values, but in some case that's not enough.

An example goal

I'm gonna illustrate you an example where create an internal DSL with a builder pattern could be useful, but first let's take a step back.

The core language of the Android SDK is Java. Well, that's already a good reason. Nobody likes Java, right? 🙂

The Android SDK offers thousands of APIs, some newer, some older. Some newer based on another older API. Some deprecated, some available only from a certain version of Android.

So many times we end up by creating a simple abstraction layer on them.

I did it many times… Then I copy-paste that code for re-use in another project. Then it grows up; I update it, improve it, expand it again; then I chose to extract it in a library, usually with a well designed DSL ( at least, that's my hope 🙂 )

Let's create a Notification

We want to inform our user that the cleaning of the cache has completed successfully.

That's a simple notification: without a body, an action, nothing… Just the bare minimum for create a Notification.

That's pretty verbose, do you agree?
Wouldn't you prefer something like this?

This code looks just a little more concise and clean, but image a real life scenario, with many other parameters. That would be a way better than the original API.

Builder pattern: how?

Let's take the most configurable block from the code above: the notification block.

It could have many parameters, some required, some optional, some parameters that exclude others ( like title: String and titleRes: Int )…

Here's a simple Builder:

Do you spot any problem here?

I spot many problems:

  • both title and titleRes are nullable and one of them is required, so we need to make an unsafe call like !!

An exception need to be thrown in this case, but we would like something that explain the problem better than a NPE, right? So what do we do? Will we add many assertTitle(), assertThis(), assertThat()? NO!

  • We need to keep calling context.getString(), context.getThat(), and so on…

Would you believe me if i tell you that you can:

  • avoid to manually retrieve resources every time
  • avoid to keep checking for nullable values
  • have not-nullable values without initialize them
  • have well-declarative exceptions without thow them or make assertions

Would you?

Would you believe me if I tell you that you can have a class like this, where title and smallIcon are not nullable while contextText is?

As you can see, we only need to call title, without manually check if it has been set, otherwise try to retrieve titleRes, check this other one for assert it's not null, etc.

In this case title is not-nullable: if it has not been set, the delegated property will check for its backing resource titleRes and, if also this one has not been set, a custom exception will be thrown by the delegated property itself.

Also contentText has a backing resource contentTextRes, but in this case we used optional, so it's nullable

I guess you also noticed that ResourcedBuilder by context(): what's that? ResourcedBuilder is a simple interface that exposes a Resources value; this interface is anonymously implemented by the invoke function declared on Context.

How did we get rid of all the context.getString()?

Well, optional and required are implementations of ReadWriteProperty that accepts ResourcedBuilder as the type of object which owns the delegated property. So our delegated property will make the dirty work.

This is the power of delegation 😎

There are some lines of code behind that and for this reason I prefer to carefully illustrate and explain them in the second part, for avoid to annoy you with a 30min story.

Don't worry, I'm not that evil, here's a Repository on GitHub were you can take a look at the code

Hope you like it. Please feel free to leave your feedback down here 🙂 See you soon! 👻

--

--