When thinking about how to create our DSL, we'll want to consider what syntax we would like to have, as well as what our solution would look like without a DSL. Let's start by imagining what our code might look like without using any kind of DSL.
Without a DSL, we might write code that looks something like this:
val order = Order("123")
order.items.put(Sprite, 1)
order.items.put(Coke, 1)
val pizza1 = HawaiianPizza()
pizza1.toppings.add(Pepperoni)
val pizza2 = BuildYourOwn()
pizza2.toppings.add(Pepperoni)
pizza2.toppings.add(Olive)
order.items.put(pizza1, 1)
order.items.put(pizza2, 1)
In this code, we're able to create all of our items in a very ordered, imperative way. It's pretty easy to follow, but there is a fair bit of repetition in the code.
We could simplify this code a bit without using a DSL as follows:
val order = Order("123").apply {
items.put(Sprite, 1)
items.put(Coke, 1)
}
val pizza1 = HawaiianPizza().apply {
toppings.add(Pepperoni)
}
val pizza2 = BuildYourOwn().apply {
toppings.add(Pepperoni)
toppings.add(Olive)
}
order.apply {
items.put(pizza1, 1)
items.put(pizza2, 1)
}
This version of the code starts to avoid some of the repetition by making use of the scoped apply calls.
What we would like to be able to do is something much more natural and human readable—something that looks more like this:
create new order
add coke
add 2 sprite
add pizza {
pepperoni
pineapple
olive
}
This code is not much more than pseudocode, but it's easy to read and understand and gives us a goal that we can target when designing our pizza shop DSL.