Sunday, May 23, 2021

Why Kotlin is Domain Specific Language?

There was this question asked to me recently by a developer and as a programmer, I can program this and tell you why kotlin is a domain-specific language? and have many advantages as a domain-specific language.

My Answer:

What Is a Domain Specific Language?

Kotlin is a great programming language with many features. One of the most amazing abilities it has is to allow developers to author DSLs.

 So let's say you have a customer who wants a manufacturing system that can assemble a fort. the customer could easily just want an Android app with many screens, but it could be fort, so let's keep talking about that. you might make some code that looks like this, a series of imperative commands to the computer.

 Create some objects and wire them together to create a fort that has two walls and a tower. This code is normal code we see everywhere throughout our projects. The code is imperative, which I use to describe code that tells the computer exactly what to do.
 
In comparison, So suppose now the customer wants something bigger and new style but fort. The new fort has four towers, four walls, a keep in the middle. Additionally, the fort has some new requirements about how towers can be connected. So you add more imperative code. It constructs the various objects and wires them together to create the final fort object. 

The code still fits fort this requirement at least. The customer is really enjoying his fort and has bigger plans for your fort building system. Now he is requesting a grand fort consisting of many towers, walls, and keeps going. Additionally, he wants to add some new kinds of structures that have additional requirements. 

You can imagine a lot of code is going to be needed just to create this complicated structure. After a lot of typing, you manage to code it and the customer, once again, leaves you alone. However You sit down at your computer to write another 1, 000 lines of configuration code but stop, maybe there is a way to make this configuration code simpler. 

How are you feeling about writing the code using your imperative style? Your initial fort construction code was only about 10 lines. The slightly more complicated fort was a little more, but then you hit this point where larger forts require thousands of lines of configuration, not only that, you can see that in the future business is good and you will be writing many more forts over and over again. 

When you encounter this type of situation, you start to look for some ways to make it easier to construct forts with less code. Now there are several ways you could accomplish this. You could improve the object model. Maybe you have objects that create parts of the fort and create some reasonable components. This is always a good idea because reducing code complexity is important. However, it may not help to make it easier to construct a fort with less code because you are still limited with your imperative programming style and you have not tried to clean up noisy syntax. 

Another option is to use a configuration file. It could be represented as JSON, for example. The JSON can describe the fort and its components, another part of your code reads into JSON and creates the fort object. The file serves as the domain-specific language for your fort object. 

The advantage of this is that you are free to express the problem in any way you like. The downside is you need to implement the parser and other tools to interpret this new syntax. 
DSLs with their own syntax like this are called external DSLs. Often, they are not a good option because external DSLs require the extra work of writing parsers and result in DSLs with no IDE support. 
Now your third option is to create a DSL written in the Kotlin programming language. You can write the DSL to be just regular Kotlin syntax, however, you will not be writing normal Kotlin code. Instead, you're going to focus on using Kotlin's features to improve the syntax and customize it for forts building. 
This way allows you to create a DSL that helps you write more concise fort building code that is more easily understood. These are called internal DSLs and I think they are the sweet spot for utilizing DSLs effectively. 

Let's look at the problem another way.

Demo: Create a List of Towers

It looks like the customer is sending you a gentle reminder, we need to add towers to the DSL. One task you might need to accomplish in a DSL is to add a list of items. Doing so requires creating a special object within a DSL implementation. To get a clean syntax for specifying the towers, the DSL implementation needs a helper class. The Helper class is focused on creating a list of TowerBuilder objects.

Now, let's look into our code how it will look  like rather explaining things 

My Main Class will build any type of forts-based customer configuration and let's look at how easy is to configure this as compared to damn any-any language in the CS field.

Before jump into code just think of a real fort or castle how it can be.

fun main(args : Array<String>) {
FortBuilder().build()
}

class FortBuilder {
fun build() {
var builder = FortBuilder()

// function sequence
builder.keep("keep")
builder.tower("sw") // these are directions south-west
builder.tower("nw")
builder.tower("ne")
builder.tower("se")
builder.connect("sw", "nw") // connects with each other
builder.connect("nw", "ne")
builder.connect("ne", "se")
builder.connect("se", "sw")

// apply
builder.apply {
keep("keep")
tower("sw")
tower("nw")
tower("ne")
tower("se")
connect("sw", "nw")
connect("nw", "ne")
connect("ne", "se")
connect("se", "sw")
connect("keep", "nw")
connect("keep", "nw")
connect("keep", "se")
connect("keep", "sw")
}

// builders
builder = FortBuilder()
builder.keep("keep").tower("sw")
.tower("nw").tower("ne").tower("se")
builder.connect("keep", "sw").connect("keep", "ne")
.connect("keep", "se").connect("keep", "sw")
builder.connect("sw", "nw").connect("nw", "ne")
.connect("ne", "se").connect("se", "sw")
val castle = builder.build()
println("result: $castle")

// use varargs for this one
builder.connectToAll("keep", "sw", "nw", "ne", "se")

// using map syntax
builder.connect(mapOf("sw" to "nw", "nw" to "ne",
"ne" to "se", "se" to "sw"))
}
}

class FortBuilder {
private var towers = mutableListOf<Tower>()
private var keep: Keep? = null
private var connections = mutableMapOf<String, String>()

fun tower(name: String) : FortBuilder {
val tower = Tower(name)
towers.add(tower)
return this
}

fun keep(name: String = "keep") : FortBuilder {
keep = Keep(name)
return this
}

fun connect(from: String, to: String): FortBuilder {
connections[from] = to
return this
}

fun connectToAll(from: String, vararg to: String): FortBuilder {
for (toConnect in to) {
connect(from, toConnect)
}
return this
}

fun connect(map: Map<String, String>) {
map.forEach { from, to ->
connect(from, to)
}
}

fun build(): Castle {
val symbols = StringSymbolTable<Connectable>()
towers.forEach { symbols.add(it.name, it) }
keep?.let {
symbols.add(it.name, it)
}

val allWalls = connections.map { (from, to) ->
Wall(symbols.lookup(from), symbols.lookup(to)) }
return Fort(keep, towers, allWalls)
}
}

data class Fort(var keep: Keep?, var towers: List<Tower>
,var walls: List<Wall>)
data class Keep(override var name: String = "keep"): Connectable
data class Tower(override var name:String): Connectable
data class Wall(var from: Connectable, var to: Connectable)

Done that's it.

how easy it is as a developer if I think of Java here believe me it will be huge lines of code and very complex objects we need to handle. So would request to make them in any other language. you will notice the difference.
here you can connect to any towers to anything and create a bridge, wall, etc.
Suppose client asked you to create any other type of fort the idea is the base configurations will remain the same I mean you need a wall, the tower you need to connect them even you can any other configuration very easily without breaking anything and you do not have to write everything from scratch this is the beauty of the Kotlin and that is why I say it says domain-specific language.

Thanks.




No comments: