Thursday, September 27, 2007

A neat trick for refactoring code

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.

4 comments:

kirillkh said...

You probably know that all modern Java IDEs can find usages on any symbol. What remains is writing a utility that goes over all the methods from the class and runs find usage on it. I'm not sure about Eclipse, but NetBeans comes with an easily accessible refactoring API (I think you don't have even write a module for that) that is built around the javac AST. I'm pretty sure you can do this with it.

Slava Pestov said...

K: Can it be done with 6 lines of code?

And remember that if I invoke 'used-externally' in the UI, the resulting words in the list will be displayed as clickable presentations...

Anonymous said...

6 lines of code? Isn't the majority of the functionality hidden in the word 'usage'?!? You should at those lines as well.

Anonymous said...

Dirk,

The point to remember is that you can do this easily in Factor using existing facilities. The question is whether or not the various Java IDE's give you, the programmer, this ease of adding a facility to the Java IDE you are using? With the simplicity that has been shown.

regards

Bruce Rennie
(God's Own Country Downunder)