Stats

Refactoring for C/C++ and C#: Let the Machine do the Work

A review of the code refactoring tools in Visual Assist X - by John Krajewski, Senior AI Programmer, Pandemic Studios.

Editorial Note

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

This is a showcase review for our sponsors at CodeProject. These reviews are intended to provide you with information on products and services that we consider useful and of value to developers.

Introduction

A favorite interview question of mine to ask a candidate for a developer position has always been, "What do you not like about the programming language you use?" A good candidate responds with understanding about his or her workflow and efficiency, how a language promotes or hinders the ability to create solid code, and (perhaps more importantly) to maintain that code as it grows.

For me, the answer comes without hesitation: my pet peeve with most modern languages is the tedium you must endure as you code; the mindless little tasks that chip away at the time I should spend creating actual design and functionality. You know the sort: updating the declaration when you change a definition, renaming a variable or function name everywhere it's used, breaking a large function into smaller ones - why are we still performing these menial tasks? It's 2006! I may not have my flying car but the least I can ask for is the machine whirring away at three billion clicks per second to lend a hand while I'm typing text into it.

And so it should be easy to imagine the enthusiasm with which I met the introduction of code refactoring into the latest version of Visual Assist X - the add-in from Whole Tomato Software that works in just about every Microsoft IDE. At last, someone has put my processor to good use while I'm writing code, with a complex parsing engine running behind the scenes, seamlessly examining my code and turning what were once tedious and bug-prone chores into something automatic. Let's take a look at the refactorings available for C/C++ and C#. (My examples are in C++, but refactoring works in C# too.)

Keeping Code Clean

What would you say is the biggest obstacle to clean code? One of the top offenders would definitely be bloated, monolithic functions, hundreds of lines long, and nearly impossible to decipher. Refactoring these types of functions into a proper hierarchy is a task which is time consuming and so frustrating, many developers succumb to the temptation of adding 'just one more line' and letting the next person deal with it.

Extract Method

The Extract Method tool makes breaking apart these large functions virtually painless - simply select the block you want to extract, give it a name, hit the button, and you're done: the new function is implemented, the definition is in the header, and the block is removed from the original function and replaced with a call to your new function. What's more, any local variables that were declared outside the block and used within it are passed as parameters! The first time I saw this, it was like a magic trick. Let's look at an example.

Here's a segment of code from a function that does a variety of things, and is ripe for breaking into smaller pieces:

If we wanted to move all the processing of the data into a separate function, we can do so easily by selecting the text, hovering over it, and using the context-sensitive dropdown box that Visual Assist X pops up.

Selecting this (or just using the hot key) brings up a dialog where you select the name, and as you can see, Visual Assist X has done the rest. The signature is already written, with the needed variables passed in (preserving const, and passing by pointer when they are larger types).

Click 'OK' and the function is created:

... and a call to this new function is added in its old home:

There's something very satisfying about making only the broad strokes of coding and letting the machine do the rest, just select it, pop it out to its own function, and repeat. It's like having a lackey to do your dirty work. The feature is even flexible enough to pull changes out of single lines - let's take the comparison out of the for-loop and put it in its own function.

Notice how it identifies what the return type should be, based on how it's used:

... and automatically plugs it in correctly:

With this tool, large blocks of code can be restructured into multi-layer hierarchies in seconds, leaving few excuses for not creating clean, encapsulated functions, and maintaining that quality as they grow.

If you're like me, though, you probably approach the idea of a machine manipulating your code with a degree of skepticism; is it really going to properly identify everything? Of course, the machine can't read your mind, but in the vast majority of cases, it identifies the signature of the new function just as I intended (while certainly creating bugs less frequently in the process than I would do it manually!) If you give bad inputs to the feature or it doesn't do exactly what you expect, the entire thing can be easily un-done (both the CPP and header will be restored with one Ctrl-Z), and you can navigate forward and backwards to visually review the changes it made with the navigation commands.

You may have noticed, these extracted functions were all created in the header - this can be easily rectified by Visual Assist X, which leads us into the next set of features it provides (which I would say are my favorite of the refactoring tools) for manipulating definitions and declarations. (Of course, the refactorings related to headers don't apply to C#.)

Keeping your Code in Sync

One of the simplest ways to work more efficiently is to reduce the time you spend repeating tasks. Unfortunately, C++ (and most modern languages) require you to keep various parts of your code in a matching state - definitions must always match the declaration made in a separate file, members must be encapsulated with 'get' and 'set' functions, etc.

These requirements give the languages considerable power from a technical standpoint, but the result for the developer is that he or she is writing the same text repeatedly. Besides being a waste of time, it's one of the easiest ways for bugs to be introduced. The creators behind the refactoring tools in Visual Assist X obviously realize these issues, and have put considerable thought into how best to streamline this decades-old workflow.

Move Implementation to Source File

This feature is a favorite for making short work of my personal code pet-peeve: unnecessarily in-lined functions (defined in the header, only because the original author was too lazy to put it into the CPP):

Both the header and CPP are fixed up with this one command:

This one is a perfect fit for an easy hotkey, since Visual Assist X puts generated functions (created by the Extract Method and other features) into the header by default, leaving you to move them to the CPP if desired.

Create Implementation and Create Declaration

If you're not just moving an existing function but creating a brand new one, here is another tool for you. Whether you like to create your functions in the header and then copy them to the CPP or vice versa, Visual Assist X has you covered, and fills in whichever one is lacking by using the appropriate command:

Encapsulate Field

Another common task that's a staple of clean code is encapsulating a member variable with "Get" and "Set" blocks. Visual Assist X has an answer for this one too:

One especially nice touch is that the text it creates for the function names is customizable using their Autotext feature:

Here, I've changed the names of the functions it creates during an Encapsulate Field call to use the Get and Set standard that I'm used to. The system is flexible enough that you could add more lines here to do some custom thing your app needs (adding a "RegisterForScript" function which acts on the variable, for example). It's like an auto-replace on steroids - it feeds you the symbol names, and lets you arrange them as you like.

AutoText is a great feature in itself which is integrated quite well with the rest of their tools, and allows you to create common blocks of code quickly and to the exact style you want (language-specific, too).

Add Member and Add Similar Member

After using Visual Assist X, you start to realize how more efficient you can be when you don't have to leave your file and location to put declaration code somewhere else. Say, I'm writing a function, and decide a class needs another member variable or function - Visual Assist X lets me add it without leaving what I'm doing.

A stub is now created in the header, allowing me to start filling it in immediately, or navigate back and continue where I was:

If you have your cursor over an existing method or member variable, you get the command "Add Similar Member" instead, which does the exact same thing as Add Member, but is streamlined by starting with the member signature of whatever is under your cursor:

It's the little additions like this that really makes the whole Visual Assist X interface feel polished and tuned to the way you work, instead of forcing you to change your style of creating code to the way it works.

Keeping your Code Understandable by Others (and Yourself)

As anyone who's worked on a large project knows, code is never completed the first time it's written; rather, it's like a living entity in that it must change and adapt as more features are added and more or different demands placed on it. As this inevitably occurs, it is often also sadly inevitable that the names and documentation fall out-of-sync with what the code actually does, usually due to the cumbersome task of performing these changes being just annoying enough to neglect. The following features automate the process of keeping your function documentation and symbol names (which are themselves a form of documentation) up-to-date.

Rename

Virtually any kind of symbol can be renamed by Visual Assist X: methods, fields, classes, variables, and method parameters. The Rename can also be started on any instance of the symbol, not just on the declaration:

Here, we rename the Data class to a more descriptive name.

Before changing any code, Visual Assist X brings up a dialog with all the references to the symbol it detected, allowing you to confirm all changes before they happen. And, should you decide against it later, the entire operation can be undone with one invocation of Undo (it fixes all files that were affected).

Change Signature

A similar feature allows you to rename the various identifiers associated with a function:

Invoking this on a function changes the parameter types and function and parameter names, and automatically updates them throughout the function as it is used. Here, we rename the members of CompareStatus to be more descriptive, and the places within the function where they are used are updated as well.

You can also change the types of parameters, return types, and function qualifiers (like const), but you will have to update those changes manually.

Find References

The Find References tool is essentially a smarter Find in Files - it looks up the symbol you referenced, and outputs all the locations it finds in a context-based search (so it won't pick up other symbols with the same name).

It puts the results in a window you can dock like any other IDE window:

The icons in the above window are especially helpful - red arrows designate places where the symbol is assigned, green where it is referenced, and the blue block is where it is defined (great for quickly scanning through when you're looking for code that changes a given variable, for example). If there are multiple entries on a single line, they will be listed multiple times, with a "-->" denoting the location within the line. There's also a 'highlight all' feature, which highlights the symbols in your source windows using different colors for assigned symbols:

This tool brings context sensitivity and deeper analysis than Find in Files, and it's faster too.

Document Method

Perhaps the most important aspect of clean code is clear, consistent documentation. There's a handy tool for helping to automate this process which you can invoke from the function definition:

This feature will create a standardized comment block above your function, using specific context-specific data about the class and function you are documenting:

Like all the features where Visual Assist X generates code for you, the style can be customized in their Autotext tool:

The various data Visual Assist X identifies from the context is exposed as special strings which you can enter here (more are available as listed in their documentation as well).

A New Approach to Coding

I've been using Visual Assist X for years, and their code refactoring tools I've described here are just one part of a massive suite of tools integrating with all versions of Microsoft IDEs in the last several years. Alone, those features are enough to make the product valuable, and they cover a wide range of ways to enhance the way you reference, view, and navigate your code. The refactoring tools, however, represent a new direction - at last there are tools that create code - that's a big step, and certainly not an easy one when you consider the number of languages and environments they support, and on top of that, adapting to the different coding styles individuals use within each of those; it is not a small problem.

The creators of Visual Assist X have focused on a core set of tasks in the programming workflow, with really solid solutions under a wide variety of coding styles, and they've done this very well - the most striking thing overall about the product is how seamless the integration is and how polished all the features perform, in every case, in every environment and language. Which is fortunate - I wouldn't accept anything less from an application that is going to be writing code for me.

There's still room to grow, of course, I can think of more things that could be automated, and more ways you can customize what gets generated, and then there is the pot-of-gold at the end of the rainbow: can they give their tool the smarts to do all these refactorings automatically, in the background, while I write? Perhaps, it's on the horizon. But let's not get ahead of ourselves, one giant leap at a time, and I've been quite impressed with this one.

Comments and Discussions

Hey I just used this stuff & I think Im happy with it . Though, I was just thinking one thing in my mind ..it is...can's we write a tool which can automatically do the refactoring on a monolothic codebase...i meant, it will seek the method codes and find the codes (with somekinda AI ofcourse :-S ) that can be refactored..and will do that on behalf of an idle programmer (like me :P) ...cause its already 2007 now ..

I'm using it for more than 6 years already.
It definitely worth it's money. IMHO, it is the only tool that
provides intellisense and refactoring for C++ in "real time".

Ref++ is slow. Unbearably slow.

Visual Studio simply does not have refactoring for C++ at all.
And C++ intellisense in Visual Studio 2005 is just a piece of garbage, IMHO.
In Visual Studion 2005, you won't be able to work on a real-life C++ project due to
that "Updating intellisense database" until you turn it off using feacp.dll hack
or buy dual-core machine.

How solid is VAX's C++ refactoring? Not that I do C++ these days. However, there was a long discussion thread in a Developer Express forum where someone was complaining that their C++ refactoring left something to be desired (i.e., it was pretty buggy). Though, to be fair it's still described as "experimental." Intuitively, I would expect VAX to be more solid in this area, simply because they're C++ specialists who have been at it for years.

Yes, sometimes odd things do happen...
But, the refactoring VA provides is almost as solid as one .NET tools provide. Also, you can encounter problems with intellisense and automcomplete if your project uses heavy template libraries like boost.
But mainly it works.

And anyways, doing refactorings "by hand" is much more error-prone, IMHO.

I first bought SlickEdit because I couldn't remember the name of a plugin I saw for VS many months ago (VAX). Then a day later I see an ad on CP for VAX and was thinking I just messed up.
But combining both of them into my development, coding has been great. Both have different things to offer. Like, SlickEdit's auto doc viewer and VAX's IntelliSense++ (just when I thought VS05 made improvements...now I'm in heaven ). And they both work with C\C++ & C#

Nice showcase, indeed I'm already totally sold on VisualAssistX.
I'm just starting to use the new refactoring functions and I must admit they can be very useful.

Anyhow I do have a couple of comments relating to the article.

The first ExtractMethod example makes no reference to iIterator.
Presumably this is a global / class member variable?
If not, surely it has been omitted from the signature?
This is particularly confusing when you later change the signature of the function.
You convert the i variable to iIterator. Surely this means the example code is now incorrect?

I also that iMaxSize is defined as const automatically, whereas i was not.
i does not appear to be modified in the extracted method (though iIterator is) so why does i not get the same const status awarded to iMaxSize?

There was some post-screencapture editing to make the lines fit right, I shortened 'iIterator' to 'i' in some cases but missed others, which led to the inconsistencies you're seeing. Hopefully you get the idea though!

Of what advantage would it be to have the article reference compilable code?
The product isn't designed to fix problems in your code (such as were shown in the example).
I see the product as a way to simplify your coding without having to jump back/forth between definition and implementation files.

The idea of refactoring is very cool! I've been eyeing it hungrily for a while now and have yet to find a good refactoring tool I can easily integrate into my development environment; this tool may be a good start. I work with a large body of legacy C/C++ code (mostly C) for embedded systems. Most of the code was created under tight time pressures so you can imagine how useful a good refactoring tool would be. The current mindset is "if it works don't touch it" because changing things is too error prone, even though *not* changing things can cost a lot of time. Since we must use a cross compiler we can't use Visual Studio for an entire IDE, but we can use it as an editor.

We have Visual Studio 6.0 in house, as well as 2003 and 2005. Does Visual Assist X work with Visual C++ Express?

Does this tool deal with preprocessor directives?

Using the "extract method" refactoring as an example, say I have a huge function with a lot of #ifdefs in it, and I want to break it down. What happens if I accidentally select code that doesn't have all the matching #ifdef/#ifndef/#else and #endif pairs? Would Visual Assist X catch and prevent that error?

Does Visual Assist X support refactoring for macros? Let's say we have a bunch of #ifdefs for a feature or hardware platform that we no longer need to support. The code is peppered is "#ifdef FOO [...] #elif BAR [...] #endif" and I want to remove support for FOO. Can Visual Assist X help?

Can VisualAssistX write/maintain the implementation stubs for me? it is tedious to having to maintain the implementation file as well as the header file. I would like to be able to write the header file, and then the relevant implementation file to change accordingly.

Very nice article! I played around with it and it works just the way I want it, but I have problems getting my own refactor autotext items in the context menu. E.g. I added my own function documentation item without a shortcut and I couldn't find a place where to add my autotext item to the context menu.

First it was a great article and a great introduction to some of the functionality of VisualAssistX. But, you missed out a vital piece of information, how to get it.

In the article you mention that the refactoring is an add-in, this is incorrect. An add-in is something which you can add to an already installed product, in the case of this refactoring tool, you must download a version of VisualAssistX which contains the tool.

It would also be better if you mentioned in the article which version of VisualAssistX (including the build) that this feature was introduced '10.3.1534'. (current is build 1535, and beta is 1538). Remember this article will be out of date quite soon.

Also, as a closure, maybe you could quickly mention a few of the other new features added to the 10.3 series of the software. This would give us existing VisualAssistX users a good idea about whether or not to upgrade.

I purchased VAX a while back and have been using it. I agree that it's faster for refactorings though it is buggy. We frequently run into cases where VAX misses a reference to something when renaming I've posted to the support forums where Feline sometimes dismisses things as "works on my machine" but I wonder about the size of the projects they test against.