There's an occasional source of bugs in my Scala code, when I do a number of operations in order to a variable, creating lots of intermediate variables.
class SomeClass(name: String) {
def doSomeThings() {
val canonicalizedName = canonicalizeName(name)
val boozbangledName = boozbangle(canonicalizedName)
val plobberedName = plobber(boozbangledName)
val flemmedName = flem(boozbangledName) // bug! should have been flem(plobberedName)
// (more code)
doAThing(flemmedName) // correct!
doAnotherThing(name) // bug! should have been doAnotherThing(flemmedName)
}
}
Is there any way to prevent this sort of bug, in any programming language - e.g. remove "deprecated" variables from scope? I could use a var
to prevent the first bug, but it still doesn't prevent the second:
class SomeClass(name: String) {
def doSomeThings() {
var fixedName = name
fixedName = canonicalizeName(fixedName)
fixedName = boozbangle(fixedName)
fixedName = plobber(fixedName)
fixedName = flem(fixedName)
// (more code)
doAThing(fixedName) // good!
doAnotherThing(name) // bug! should have been doAnotherThing(flemmedName)
}
}
}
While getting confused with the variable names may indicate bad naming, duplication or violation of the law of demeter, it is actually possible to implement a "val-deprecation" feature in Scala using macros.
As I have just started learning how to write macros I cannot provide you a satisfying implementation, but - to illustrate what I have in mind - I tried to come up with the most trivial implementation: Checking whether the name of the val is contained in the expressions. Also, the macro only returns a
Unit
expression, which could be generalized using generic type parameters. However, it should be possible to come up with a better looking, more powerful implementation.Note that macros need to be compiled before your other code, so you need to implement them in a separate project.
The naive macro implementation could look as follows:
Which would produce errors at compile time, if
action
contains the identifier of the providedval
.Note that, according to SI-5778, using
Tree
instead ofExpr
and thereby allowing call-by-name parameters is only possible since Scala 2.11.