When developing a DSL, what is the cleanest way to limit the scope of an implicit variable and simultaneously hide the fact that such an implicit variable is defined?
As an example, this is the desired behavior...
object External
{
def funNeedingValue(implicit a : String)
{
println(a)
}
}
object Main extends App
{
useValue("Hi") {
// Implicit string "Hi" is only defined in this block
External.funNeedingValue // Prints "Hi"
}
External.funNeedingValue // Compilation error: No implicit String defined
}
The following get close, but do not have all of the desired properties...
// The following works, but does not hide the fact that there is an implicit
// variable defined.
object Main extends App
{
{
implicit val implicitValue = "Hi"
External.funNeedingValue // Prints "Hi"
}
External.funNeedingValue // Compilation error: No implicit String defined
}
// The following hides that there is an implicit variable defined, but breaks
// the scoping requirement and destroys thread safety.
abstract class Parent
{
implicit var implicitValue = ""
def useValue(valueToMakeImplicit : String)(f : => Unit)
{
implicitValue = valueToMakeImplicit
f()
}
}
class Child extends Parent
{
def go()
{
useValue("Hi") {
External.funNeedingValue // Prints "Hi"
}
External.funNeedingValue // Scoping issue: also prints "Hi"
}
}
object Main extends App
{
new Child().go()
}
// The following works, but is harder to read and still doesn't really
// hide the implicit value
object Main extends App
{
def useValue(valueToMakeImplicit : String)(f : String => Unit)
{
f(valueToMakeImplicit)
}
useValue("Hi") {
implicit value : String => {
External.funNeedingValue // Prints "Hi"
}
}
External.funNeedingValue // Compilation error: No implicit String defined
}
You could make a macro which transforms
useValue("Hi") {
// Implicit string "Hi" is only defined in this block
External.funNeedingValue // Prints "Hi"
}
into
{
implicit val iString: String = "Hi"
External.funNeedingValue
}
I don't think it's possible to do better than your last example without macros.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With