Whidbey Refactorings: Rename
Let's start by talking about Rename. I view Rename as being one of the “Tier 1” refactorings – the refactoring we absolutely must provide, and which must be of the highest quality. They must be fast, reliable, and easy to use. You’re going to use them often, and we want you to like them a lot.
What does it look like?
- Place the cursor on a name
- Right click, select Refactor->Rename
> Prompt appears for the new name. - Type new Name
- Hit OK
> All uses (“references”) of that entity get updated to the new name.
There’s also an option to see a preview of the changes before they get applied. I think you’ll use the preview the first time, and then turn if off. You don’t need it when the refactoring tool is reliable; you’ve got more important things to do.
What kinds of things can you rename?
Just about anything. The UI is pretty much the same for namespaces, types, fields, locals/args, and methods. For methods we will offer to rename overloads as well.
Will you fix up comments, too?
I argued that we should not support fixing up comments. Our refactorings are designed to be reliable – you can know that when you use them, the result will be what you expect. But we can’t really do comment fixup reliably, since it’s prose, not C# -- the semantics aren’t well defined.
Consider:
class C
{
// 'i' is my favorite variable.
int i;
int F(int i) // <--- rename 'i' here
{
return i == 0 ? 1 : i * F(i);
}
}
Go to the marked line & rename ‘i'. If you ask us to update comments, we’ll change the one on the field, as well. That’s probably not what you wanted, but there’s no way for us to know that.
In my not-at-all-humble opinion, if you want to update comments, you should use Find & Replace in Files, instead of the Rename Refactoring. Find/Replace is not very smart, but you expect that, and you already know how to manage it to get the result you want.
However, every time we showed people Rename, their first question was “Will you fix up comments, too?” So, we are including an option to fix up strings.
Can I toggle off specific changes in the Preview?
Normally, no.
If you’re a Refactoring purist, I’ll tell you that we applied the definition of Refactoring (specifically, the “leaves its behavior unchanged” part). If you could toggle off a specific reference, the behavior would change. (Specifically, your code would go from legal to C# to not legal C#.)
If you’re a Refactoring pragmatist, I’ll tell you that Find & Replace in Files has appropriate user interaction model for this kind of activity.
If you elect to Search in Comments, then you get some checkboxes for the comments.
Can I rename across projects?
Yes, but only if they’re C# projects. If you have VB and C# projects in the same solution, the VB references won’t be updated.
We have some smarts about renaming between the forms designer, the editor, and the solution explorer. For example, if you follow 1-class-per-file, and you rename a file, it’ll rename the class, too.
What are the hard parts of implementing Rename?
Find the right definition. If you rename from a reference, we gotta figure out which something you want to rename.
Find the right references. We need to look in opened & closed files, this project & other projects, etc.
Don’t break your code. There are situations where are rename will change the semantics of your code, but leave it legal. We need to be careful to detect these situations.
Dealing with illegal code. Actually, this issue spans all refactorings. Purists don’t care, because they don’t refactor unbuildable code. They built & ran their NUnit tests 30 seconds ago, and they’re about to do it again. But if you don’t work that way, you probably expect Rename to work while your code is still “in progress”.
Your feedback.
Reading this blog, do you think we’re making the right choices in our Rename design?
Are we providing the functionality you expect?
Are there parts of this feature description that look like a waste of our efforts?
When commenting, say where you put yourself on the “Refactoring Purist” scale.
Comments
- Anonymous
April 08, 2004
On a Refactoring Purist scale (1 being least... pure) I put myself at about an 8. There are rare occasions when refactoring doesn't really help an application, and those are mostly tiny apps. Rename looks perfect. I agree that you shouldn't waste your time trying to fix up comments. Work on another more worthwhile refactoring tool.
Keep up the good work, look forward to using Whidbey in production. - Anonymous
April 08, 2004
On a refactoring purist scale, I put myself at 5. I refactor code by using rename frequently, but I do not run unit testing (such as NUnit) each time after refactoring.
Comments: I agree that the comments should not be fixed up except those XML comment elements such as <param>, <see>, <seealso>. And its better to show a list of comment lines that contains the name refactoring.
Dealing with illegal code: I think this is less important, refactoring should not be applied to uncompilable code. - Anonymous
April 08, 2004
The comment has been removed - Anonymous
April 08, 2004
Perhaps a compromise for comments would be to fix up XML comments when parameters are specifically stated. For example...
///<summary>
/// i do not like i to change here.
///</summary>
///<param name="i">iterator</param>
public void DoSomething(int i)
{
//...
}
The "i" in the summary would not change, but it would in the <param> tag. - Anonymous
April 08, 2004
I agree with haacked. I use CSharpRefactory extensively and one of the most obviously lacking features is that I can rename parameters easily, but it misses the XML <param> tags. - Anonymous
April 08, 2004
Why deal with illegal code at all? Just make the programmer have something that compiles before allowing refactoring. I believe this is the way Eclipse does it. - Anonymous
April 09, 2004
You could make that an option of the IDE, e.g.
[] allow refactorings only on legal code - Anonymous
April 09, 2004
The comment has been removed - Anonymous
April 09, 2004
One of my reasons to refactor is to eliminate the need for comments (guess that makes me 'pure'). But I agree you should refactor the xml tags, as they are not comments in the traditional sense. - Anonymous
April 10, 2004
I don't think I even rank on the "refactoring purist" scale, though I can imagine finding the rename feature quite handy. However, while reading your post, I realized what I really want is for the regular Find and Replace features to provide an option allowing me to include, exclude, or explicitly target comments. - Anonymous
April 11, 2004
I'm pretty low on the refactoring purity scale although I do refactor occasionally. I started using some commercial refactoring software recently and I've been refactoring more frequently since. Although it has a few dozen refactorings and metrics and audits and such, about the only ones I use are renaming and moving. Rarely I'll extract a method or constructor although I often do that by hand. It's got basically all the features described here for Whidbey. There's even a preview window which I just click through without reading since it can't be disabled.
The one thing that bugs me though is the speed. I've got some code I've been working on for a few years and there's a few thousand classes and maybe 1M lines of code. Renaming a class or public method on that can easily take a minute or two. I made a subset of about 100K lines and a refactoring took maybe 5 seconds. Suddenly I was WAY more likely to try things out and experiment.
If a rename or move takes more than about 10 seconds I'm likely to go find something else to do while it's working. Or put it off until later (or never). The time really adds up when I want to rename 30 or 40 things. So I'd be willing to trade things like comment fixup and working on unbuildable code for speed and large project support. - Anonymous
April 12, 2004
Nicholas: Thanks, this is excellent feedback. We definitely need to keep an eye on the perf of refactorings if we want folks to use them a lot.
Eric: I have also wanted that behavior. I'll forward the request to the right folks. - Anonymous
April 12, 2004
I think the goal of being able to perform refactorings on unbuildable code and the goal of obtaining reliablity are mutually exclusive.
The key to performing the refactorings reliably is to have proper variable bindings setup. However, recoving from errors in the parser or lexer might "gobble up" perfectly nice identifiers that won't have an opportunity to have bindings attached to them.
This could be resolved by requiring that the code parses, but not necessarily type checks in order to allow refactoring to occur, and then insuring that references to "eroneous types" are handeled consistently. However, I think this could be confusing to users. To a novice programer there isn't much of a distinction between type errors and parsing errors and they might view the refactoring as "not behaving consistently". The requirement that code must build before being able to be refactored seems more concrete. If allowing broken code to be refactored is designed to help novices, I would exclude it, because I think novices might have the most trouble with it. - Anonymous
April 13, 2004
I wish to be able to use refactoring when my solution contains some projects that will not compile.
Think of a normal sized system (say 300 projects and 3M lines of code), the fact that one project does not compile should not stop refactoring working, provided that ALL projects that DIRECTLY depend on the project that contains the class I am changing do compile, there need not be any problems.
Having the built in refactoring will be one of the best bits of Whidbey, I hope it will made all systems I work on a lot easier to understand. - Anonymous
April 14, 2004
Ian: thanks for the feedback. - Anonymous
April 16, 2004
A month ago I would have said your implementation is perfect, but having seen the Rename refactoring implementation of ReSharper, I say they've got it right. Ditch in-comments search option and with it the dialog and do the refactoring inline. It is WAY smoother and more productive that way. - Anonymous
April 21, 2004
What about changing what you know you can, and providing a refctoring report in the task list for 'candidates' like the comments. Also, I would say only buildable code should be 'refactored' otherwise you are not really refactoring, you are just renaming. The feature is simple now, but if the expectation starts as "refactor any time" then as you try to implement helpers for more complex refactoring the water gets muddier and muddier and your going to want even more to pull the ability to refactor unbuildable code. - Anonymous
July 25, 2004
The comment has been removed