A neat trick for refactoring code
Thursday, September 27, 2007
So today I’m going to be cleaning up one of the vocabularies involved in
code generation in the optimizing compiler. Each vocabulary has a set of
words which are used by other vocabularies – the “public interface”,
and implementation words, those only used to implement the interface. I
want to rewrite the generator.registers
vocabulary but keep the public
interface as close to its current state as possible. Trouble is, the
public interface is not well-defined here; this vocabulary does not use
<PRIVATE
and PRIVATE>
. However, this is not a big problem, since I
can just write a tool:
: used-externally ( vocab -- words )
dup words [
usage
[ word? ] subset
[ word-vocabulary = not ] curry* contains?
] curry* subset natural-sort ;
How does this work? It takes the list of words in a vocabulary, then for each word, checks if the usages of that word include any words outside of this vocabulary. If the answer is affirmative, it adds this word to the sequence that is returned.
Using this tool I found out that generator.registers
vocabulary only
has a handful of words which are used externally, and so it should be
easy to do a radical refactoring which doesn’t require many changes to
other modules.
It is hard to articulate how powerful this is. Not only is the Factor
listener is a great way of testing code, it also provides a way to
interact with the system on a meta-level. I wonder how much work it
would be to implement something like used-externally
in a conventional
IDE such as Eclipse; I’m sure all the pieces are there
(cross-referencing, etc) but it can’t be that easy to just glue things
together like that.