Investigate Groovy DSL capabilities
Closed this issue · 2 comments
Take a look at the DSL capabilities of Groovy and sketch up a first version of our custom, mostly declarative DSL.
First of all, Groovy has extremely wide DSL capabilities, so it's a perfect choice for us. Without doubts it can be said, that there's nothing we can't do with Groovy, so we can make the most natural and performant DSL.
Although Groovy is widely used for creating DSLs, it wasn't that easy to find useful resources.
Some good links and books I could find:
Official DSL Development Documentation
Going to Mars with Groovy Domain-Specific Languages
Slideshow that covers a variety of techniques that can be used in order to create an easy-to-use DSL in Groovy.
BOOK: Groovy for Domain-Specific Languages
A book from 2010 that gives an introduction and an advanced sight into Groovy DSL development. Claims to explain the trickiest methods and concepts.
BOOK: DSLs in Action
Not quite Groovy (only contains one Groovy chapter) but provides some really usefu insights about DSLs in general.
Thoughts on the high level declarative DSL
DSLs and declarative style make a good fit together, so it was a great idea not to choose the imperative approach.
Programs that control the objects that belong to a player contain various preconditions and actions that should be performed when the preconditions are fulfilled. Consider the following piece of code:
all workers {
if enemy is seen {
move towards base
}
}
This language feels natural because it's very close to the way we'd express ourselves. Also, it's can be easily implemented, so this seems like a win-win situation at first.
However we should not forget the fact that the most expensive thing in codes like the above is not performing the actions but evaluating multiple and complex preconditions very frequently.
For example, if the player had 100 workers, this code would look something like this in plain old imperative style (not using foreach
or size()
for illustration purposes) :
int viewRadius= 5;
for (int i = 0, n = 100; i < n; ++i) {
boolean enemyNearby = hasInRadius(workers.get(i), viewRadius, ENEMY);
if (enemyNearby) {
moveTowards(base);
}
}
If the viewRadius
is 5, it means that we're searching for enemies in a circle with r = 5
. So int the worst-case scenario, we need to check approximately 78 tiles for each worker which sums up to checking 7.800 tiles!
Of course, this is not a problem with the declarative approach, it's just a consequence of our high level language. This little code example just showcases the fact that just in a few lines of code we can write something that's expensive to run.
I'd like to leave this example here to remind us to possibly figure out some caching method or some other advanced technique that helps speeding code like this up.