Pizza DSL with Kotlin
DSL is not a programming language, it is the term used to describe any application API which is designed in a way such that users can easily use it in there domain to solve problems with out knowing any programming language. Domain Specific Languages is used to solve problems in a specific field or domain. For example; SQL is based on a natural language so users can easily create there queries to get data from database. Learn more about DSL here. Below are some of the examples of DSL’s and there applications;
- HTML -> Render web pages
- SQL -> Query database
- XML -> Data transfer between applications
In this article I am using Kotlin to create a Pizza DSL. We can not really order a pizza with this but my intention is to develop a new DSL so we can configure a pizza and call order() on it so it prints pizza configuration on the console. This is a fun way to understand how DSL work and also we can learn some kotlin’s programming features. We are going to use below features of Kotlin to build this DSL.
Kotlin have many features which are helpful in developing DSL’s so lets create a basic shell and then we will build-up our pizza API on it.
<1> Initial Pizza class with only order function and it just prints the instance. Nothing much in this class.
<2> Declared a pizza function which takes an extension function of Pizza and it returns a new Pizza instance. If you are new to extension function then read more about it here.
<3> We are calling pizza function with out passing any thing to lambda and then calling order() on it.
Pizza size (Large or Medium ??)
Pizza order starts by mentioning the size so lets create some functions to handle size of the pizza.
<1> Our Pizza class supports medium and large size pizzas and by default it is medium sized so we initialized size with Medium
<2> Implemented functions to handle each size: large and medium. These functions take extension function on Pizza then it sets the related size and then calls the passed function.
Cheese it up
We need to allow users to add sauce and cheese. We are going to give user to choose three levels or cheese (light, normal and extra) and three types of sauces (Marinara, Garlic parmesan, Alfredo)
<1> Declared enums to maintain Cheese level and Sauce types.
<2> Implemented two functions to add sauce and cheese. These functions will just set the passed values into the class level fields.
<3> Calling add function to add sauce and cheese. These functions are part of large pizza context.
Allow users to add toppings and also what if users want toppings on one side? so lets implement this.
<1> Two enums are used to maintain Veg and Meat toppings. These enums extend a common interface Topping
<2> toppings will create new context to add toppings on the pizza. half will create new context to add toppings on half part of the pizza and add will take variable arguments to add toppings to the list.
<3> call add by passing some toppings which are added to the list.
<4> creates new context to add toppings on half side of the pizza.
Print pizza information
Display configured pizza information on the console.
<1> Overload toString to return string representation of pizza instance. This will use multi-line string to return pizza details.
Full code of this code available on gist
We used many kotlin features to develop pizza DSL. Using this DSL we can configure pizza and print its information to the console.