I have some vanilla Scala code that looks like this:
addCooker(new Cooker(getOvenState(), cookingTime, CookieNames.GingerSnaps) {
override def cook(customer: Customer, priority: Priority): Boolean = {
// Use `customer` and `priority` to cook a cookie and return true if successful.
???
}
})
I.e. I create a callback-like Cooker object that's passed to an addCooker method. CookieCutter takes some values (cookingTime etc.) that are available when calling addCooker (these are passed to its ctor) and it takes some values (customer etc.) that will only be available at some later point in time (these will be passed as arguments to its cook method).
I'd like to create a DSL where I can write this as:
addCooker(getOvenState(), cookingTime, CookieNames.GingerSnaps) {
// Somehow make a `customer` and `priority` value (that are not available at
// the time `addCooker` happens) visible to the code within this block.
}
I could declare addCooker as a method like so:
def addCooker(overState: OvenState, cookingTime: Duration, name: CookieName)(
block: () => Boolean
): Unit = ???
But I don't see a way to make cookingTime etc. available such that they can be used within the lambda passed as block.
The best I can do results in something like this:
addCooker(getOvenState(), cookingTime, CookieNames.GingerSnaps) { (customer, priority) =>
true
}
Normally, this would be good enough for me but in this situation, hundreds of such blocks will be written (and there'll be lots of different but similar constructs) and a DSL where many of the values are just there rather than one needing to always declare them as parameters would be ideal.
I guess one way is to make customer etc. protected var variables of the class where the addCooker calls are being made, i.e. they'd be visible not just to my { ... } block but also to the logic that calls addCooker (but without yet being set to anything meaningful).
PS are there any good guides to the kinds of non-obvious tricks that you need to use to create DSLs? I found lots of guides that didn't go very deep (focusing on little more than using implicits to do type conversions or do fun things with operators). The only substantial thing I found was DSLs in Action but it was written in 2010 and uses Scala 2.8 - I imagine the thinking on many things related to implicits and the like has changed noticeably since then.
If the above snippets are unclear, you can them (with supporting stubs such that things will compile) here:
https://gist.github.com/george-hawkins/a9db64f05e14ea7d191bc4cf85dd64f6