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?



  1. Place the cursor on a name

  2. Right click, select Refactor->Rename
    > Prompt appears for the new name.

  3. Type new Name

  4. 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 (22)

  1. Chad Thiele says:

    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.

  2. smartkid says:

    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.

  3. B.Y. says:

    I’m thinking about the social implications of this feature.

    Currently, the coding convention zealots don’t go about renaming names they don’t like, because it’s just too much hassle and too error-prone to search and replace.

    Now, if you provide a "fast, reliable, and easy to use" renaming feature, you’re bringing the holy war to a new level, man.

    Imagine loading up your project one day, and find all your variables have been renamed by the true believer on the team. Now what do you do ? Do you let it pass ? Do you rename it back ? Or do you go kick him in the testicles ? I can see the fun coming.

    And imagine the potential for pranks. Hey, let’s check out Jaybaz’s class, rename bAllowEdit to temp, rename bIsChanged to bAllowEdit, and rename temp to bIsChanged.

    I don’t know what’s a “Refactoring Purist”, but I don’t like being a "purist".

  4. 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.

  5. RichB says:

    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.

  6. Brian C Robinson says:

    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.

  7. Martin Bennedik says:

    You could make that an option of the IDE, e.g.

    [] allow refactorings only on legal code

  8. Mark says:

    Refactoring Scale: 8

    Rename in strings. I don’t really care about having the rename refactor work in true comment strings. Xml Documentation is another matter however. As another commenter said, having the parameter, class, XXXX item renamed in the Xml tag is a must, but if you leave the value of the element alone that’s fine. Justification: If I am generating XmlDocumentation and my build currently has zero errors/warnings, and then I do do a rename refactoring on something, if the XmlDocument tags are not updated, the compiler will start spitting out warnings. As a user that would make me feel very uncomfortable.

  9. Thomas Eyde says:

    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.

  10. 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.

  11. Nicholas Allen says:

    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.

  12. 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.

  13. Scott Wisniewski says:

    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.

  14. Ian Ringrose says:

    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.

  15. Ian: thanks for the feedback.

  16. 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.

  17. Stephen Johnston says:

    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.

  18. Anonymous says:

    Larkware: The Daily Grind 344