43

I see questions similar to this with regards to parameter names that match properties on the class, but I can't find anything regarding using a parameter name that is the same as the parameter type name except for casing in C#. It doesn't seem to be a violation that I can find, but is it considered bad practice? For example, I have the following method

public Range PadRange(Range range) {}

This method takes a range, and returns a new range that has had some padding applied. So, given the generic context, I can't think of a more descriptive name for the parameter. However, I'm reminded of a a tip I picked up when reading Code Complete about "psychological distance". It says

Psychological distance can be defined as the ease in which two items can be differentiated...As you debug, be ready for the problems caused by insufficient psychological distance between similar variable names and between similar routine names. As you construct code, choose names with large differences so that you can avoid the problem.

My method signature has a lot of "Range" going on, so it feels like it may be an issue with regards to this psychological distance. Now, I see many developers do the following

public Range PadRange(Range myRange) {}

I personally have a strong distaste for this convention. Adding a "my" prefix to variable names provides no additional context.

I also see the following

public Range PadRange(Range rangeToPad) {}

I like this better than the "my" prefixing, but still don't care for it overall. It just feels overly verbose to me, and reads awkwardly as a variable name. To me, it's understood that range will be padded because of the method name.

So with all this laid out, my gut is to go with the first signature. To me, it's clean. No need to force context when it's not needed. But am I doing myself or future developers a disservice with this convention? Am I violating a best practice?

  • 35
    If you can't come up with a more descriptive parameter, Range range is fine. – Robert Harvey Apr 19 '18 at 15:44
  • 21
    In this situation, the IDE will color 'Range' and 'range' differently so it's really easy to see that one is the type and one is a variable name. – 17 of 26 Apr 19 '18 at 15:57
  • 10
    Yeah, I recall that. It's in their design guidelines as a consideration. "CONSIDER giving a property the same name as its type." docs.microsoft.com/en-us/dotnet/standard/design-guidelines/… – Jason Tyler Apr 19 '18 at 19:01
  • 11
    Also fine: Range r (at least for a short method body) and Range toPad. – Bergi Apr 19 '18 at 19:47
  • 19
    I always considered the "my" prefix as something that is done in example code where its used to indicate to the reader that a name should be changed to something else depending on the context. It not something that should actually end up in any real code. – kapex Apr 20 '18 at 8:41
100

Don't overthink this, Range range is fine. I use such kind of naming for more than 15 years in C#, and probably much longer in C++, and have never experienced any real drawbacks from it, quite the opposite.

Of course, when you have different local variables in the same scope, all of the same type, it will probably help to invest some mental effort to distinguish them properly.

  • 6
    Another exception I'd add is when the instance is having a particular action done on it. There's a bit of room for being more descriptive as to why the parameter is needed for example. Wack(Bozo bozoToBeWacked) Even more so if the parameter is optional and describing what the object in that scenario means/what it will impact. My rule of thumb if it isn't obvious without looking at the code what the parameter does then it needs a better name and/or comments. – Mike Apr 19 '18 at 19:40
  • 17
    I would regard Wack(Bozo bozoToBeWacked) as an example of a redundancy in the variable name that is amply expressed by the method itself (and thus undesirable per the original question). Wack(Person bozo) is more semantically valuable, however, as it implies that it is expected for only bozos to be wacked. – Miral Apr 20 '18 at 6:22
  • 2
    In the case you mention in the second paragraph, I will often rename the parameter to something like initialRange. It is still very generic but doesn't have nearly the same level of distaste as myRange. – Jaquez Apr 20 '18 at 13:26
  • @Miral: It becomes more relevant in cases such as Punch(Bozo punchingBozo, Bozo bozoToBePunched). Detailed naming is more relevant when you have to distinguish between multiple things (which are semantically described with pretty much the same words). OP's suggestion of Range rangeToPad is not necessary in his one parameter method example, but might be incredibly necessary for a method that takes in several Range objects. – Flater Apr 20 '18 at 13:36
  • 7
    @Flater Punch(Bozo source, Bozo target) would do the job – Thomas Ayoub Apr 20 '18 at 15:22
17

I do this all the time, it is giving me great piece of mind. If it is an argument passed to a constructor that needs to be assigned to a member, my member would be named range as well and the assignment would be

this.range = range;

And I would typically have a property named Range.

They are all the same thing, only differing in context so it makes sense to maintain a single name and you will have to remember only one name. It is one thing, the differences are purely technical.

You should be strict with fully qualifying members with "this." though, but that is what StyleCop is for.

StyleCop side note

Controversy guaranteed!

To those advocating against the use of "this.": I have seen _, m, m_ and just nothing. The language itself is offering us a perfectly clear, unambiguous universally recognizable way of indicating we are dealing with a class member. Why on earth would you want to make up your own way that mutilates already perfect names?

The only reason I can think of it that it is a legacy habit from the C era, when it actually made sense to do it because there was no other way.

"It is more characters!" Seriously? "Compile time will skyrocket!" Seriously? "I will have to lift my pinky when typing it!". As if typing time had any significance in the total development time.

I recognize that any style different from what you are used to will raise some opposition. But using this consistently is hard to argue with. Here's how it works for me: Before I push a new code file I run StyleCop and it will find a number of members lacking "this" qualifiers. I put "this." on the clipboard, run by the members and insert. No effort at all.

StyleCop does a lot more than this (haha). There are so many ways a developer can (only considering code formatting) frustrate the maintenance work of his successor. StyleCop prevents most of them. It is invaluable.

If you are new to it: it typically makes you grumble for a week or two and then you will love it.

  • 19
    "You should be strict with fully qualifying members with "this." though," -1. Do not use this except when essential. It's just noise otherwise. Use _range for the field and this is never needed except in extension methods. – David Arno Apr 19 '18 at 19:19
  • 12
    I concur with @DavidArno. 'this' is just pure noise. 'Range' is a property, '_range' is a field, and 'range' is a parameter. – 17 of 26 Apr 19 '18 at 19:24
  • 8
    @David If the variable is a class member, it IS essential and beats any arbitrary prefix to signal you are looking at a class member rather than an argument or a local variable. – Martin Maat Apr 19 '18 at 19:26
  • 6
    My IDE would shoot fireballs the second I would assign a variable to itself. – Koekje Apr 19 '18 at 21:43
  • 21
    @DavidArno Care to explain why the "noise" of _ is preferable over the noise of this.? I would argue one has meaning enforced by the language (and typically have syntax highlighting) while the other does not. – Clint Apr 19 '18 at 22:07
9

My self-guidance on naming methods, parameters and variables is pretty simple:

  1. If the name contains the type that is being passed in or returned, you're doing it wrong.
  2. Name things by what they are intended for, not what they are.
  3. Always remember that code is read more than it is written.

Thus the optimal method signature, in my opinion, would be:

Range Pad(Range toPad)

Shortening the method name is self-explanatory.

The parameter name toPad immediately tells the reader that that parameter is probably going to be modified in-place by being padded, then returned. In contrast, no assumptions can be made about a variable named range.

Further, in the actual body of the method, any other Range variables that are introduced would (should) be named by their intent, so you might have padded and unpadded... toPad conforms to those naming conventions, but range just sticks out and doesn't gel.

  • 3
    padded/unpadded sounds good for local immutable variables. But if there is a mutable toPad parameter, then after the padding has been done the name toPad does not fit any more (unless the result is returned immediately). I would rather stick to Range range in those cases. – kapex Apr 20 '18 at 8:59
  • @Kapep I'd call it just result. It gets modified and returned. The latter is clear from the name and the former follows, as returning an unmodified argument makes no sense. – maaartinus Apr 20 '18 at 11:13
  • From the signature, the Pad method returns a Range. That, to me, implies that the one I've passed in will be preserved, not modified in-place, and a new, padded Range will be returned. . – Aaron M. Eshbach Apr 20 '18 at 13:47
  • 1
    I'm not sure what to think of your advice. Pad(toPad) feels kinda wrong IMHO. You make a good point of defending your point of view though. You get a +0 from me! :) – Eric Duminil Apr 22 '18 at 15:25
  • In the question it states that it "returns a new range that has had some padding applied". I agree with your naming for what you think the scenario is, but for the actual question I'd go for something like Range CreateRangeWithPadding(Range source) – Richard Willis Apr 23 '18 at 14:06
3

For naming of code elements (types, variables, functions, anything), the key question to ask yourself is

If I make a typo, will the compiler find it for me?

The worst kind of typo-based bug is one where the code compiles and runs, but gives different behaviour from what you expect, for reasons which are subtle. And since it's due to a typo, it's usually very hard to see when you're inspecting the code. If a typo will stop the code compiling, then the compiler will flag up the line causing the problem, and you can easily find and fix it.

For your situation where the type and variable differ only in capitalisation, this will always be the case. (Or nearly always - with sufficient effort, I'm sure you could make it work, but you'd have to really try.) So I think you're OK there.

Where you would need to be concerned would be if there were two variables, methods, functions or properties in current scope called range and Range. In that case the compiler probably will let it through, and you're going to get unexpected behaviour at run-time. Note that that's two of any of those types of code element, not just "two variables" or "two functions" - all of those can be implicitly cast to each other, with resulting carnage when it runs. You might get warnings, but you can't guarantee anything more than that. You have similar issues if you had two types declared called range and Range.

Also note the same applies to the Hungarian notation style, where names are prefixed with one or more characters to say something more about whatever it is. If you have a variable called Range and a pointer to it called PRange, it's easy to accidentally miss the P, for example. C# should catch this, but C and C++ will only give you a warning at most. Or more worryingly, suppose you have an double version called DRange and you downsample that to a float version called FRange. Use the float one by accident (which is easy since the keys are adjacent on a keyboard) and your code will kind of work, but it'll fall over in strange and unpredictable ways when the process runs out of resolution and underflows.

We're no longer in the days where we had naming limits of 8 characters, or 16 characters, or whatever arbitrary limit. I've sometimes heard novices complaining about longer variable names making coding take longer. It's only ever novices who complain about this though. Serious coders know that what really takes time is figuring out obscure bugs - and bad choice of naming is a classic way to drop yourself in that particular hole.

  • Just a note for the readers - for C#, people should really avoid Hungarian Notation. While it was useful in older times when syntax highlight wasn't a thing or was limited, nowadays it really doesn't help. – T. Sar - Reinstate Monica Apr 20 '18 at 12:07
  • @T.Sar Even back in the day, I hated it with a passion! As you say, better IDEs have solved the problems it was aimed at, but it still appears every so often. You'll still see it if you need to talk to the Windows API, for instance, for historical reasons. I didn't want to totally bash people's preferred styles if they really like it, but I did want to use it as a hook for showing that upper/lower case isn't the only way you can screw up naming. – Graham Apr 20 '18 at 12:13
  • I'm aware that you're not proposing the use of Hungarian Notation, but I'm also aware that young devs have a enormous weakness for things with cool names. Being able to say "My code is written in this super secret ninja coding style - the Hungarian Notation!" may sound irresistibly cool to the younger minds. I've seen too many devs fall prey to the hype of cool words... Hungarian Notation is pain give the form of source code x.X – T. Sar - Reinstate Monica Apr 20 '18 at 12:19
  • @T.Sar True enough. "Those who do not remember the past are doomed to repeat it" and all that. :/ – Graham Apr 20 '18 at 14:04
  • 1
    Are we talking about the original Hungarian notation or how it was grossly misinterpreted by Microsoft (near "the documentation writers on the Windows team inadvertently invented what came to be known as Systems Hungarian" and also in interview of Joel Spolsky by Leo Laporte on Triangulation episode 277, 2016-12-12, 04 mins 00 secs - 06 mins 35 secs)? – Peter Mortensen Apr 21 '18 at 6:34
1

One anecdote I would like to add, while Range range this is syntactically legal, it could make things more challenging to debug or refactor. Looking for that one variable named "range" in a file with lots of variables of type Range? You may end up doing more work later as a result of this naming choice.

This is largely context-dependent though. If it is a 30 line file, my statements don't really come into play.

  • 7
    Most people use tools that distinguish between types and parameters or variables, for Windows development. What you describe reminds me of the good old grep days on Unix. – Frank Hileman Apr 20 '18 at 1:35
  • 1
    @FrankHileman It might surprise you, but Unix is still alive and grep is still in use (:D). As grep is by default case-sensitive, the mentioned problem just doesn't exist. However, even we, terminal-addicted windows-haters, rarely use grep for source code as the IDE is much better at common searches. – maaartinus Apr 20 '18 at 11:09
  • I think that we agree that the platform is not the point. grep is a great tool, but it is not a refactoring tool. And refactoring tools exist on every development platform I've used. (OS X, Ubuntu, Windows). – Eric Wilson Apr 20 '18 at 12:17
  • @EricWilson At one time, grep and sed were the only refactoring tools on unix. – Frank Hileman Apr 20 '18 at 20:31
  • @FrankHileman Just because something is used as a refactoring tool doesn't mean it is one. I can refactor in notepad, but that doesn't make it more than a text editor. – Eric Wilson Apr 22 '18 at 1:12
1

I think you can use Range range nowdays for one reason: syntax highlighting. Modern IDEs usually highlight the type names and the parameter names in different colors. Also a type and a variable have a considerable "logical distance" not to be easily confused.

If this wouldn't be the case I would consider a different name or trying to enable a plugin/extension that can do this syntax highlighting.

0

When a function is generic, it stands to reason that the parameters will be generic, and thus should have generic names.

Not what you're saying, but I've seen functions that perform a generic function that have parameter names that are misleadingly specific. Like

public String removeNonDigits(String phoneNumber)

The function name sounds very generic, like this could be applied to many strings in many situations. But the parameter name is oddly specific, making me wonder if the function name is misleading, or ... what?

So sure, instead of saying Range range, you could say Range rangeToPad. But what information does this add? Of course it's the range to pad. What else would it be?

Adding some arbitrary prefix, "my" or "m_" or whatever, conveys zero additional information to the reader. When I've used languages where the compiler does not allow a variable name to be the same as a type name -- with or without case sensitivity -- I've sometimes put on a prefix or a suffix, just to get it to compile. But that's just to satisfy the compiler. One could argue that even if the compiler can distinguish, this makes it easier for a human reader to distinguish. But wow, in Java I've written statements like "Customer customer = new Customer();" a billion times and I never found it confusing. (I've always found it a bit redundant and I rather like that in VB you can just say "dim customer as new Customer" and you don't have to give the class name twice.)

Where I DO object strongly to generic names is when there are two or more instances of the same type in the same function. ESPECIALLY parameters. Like:

public Range pad(Range range1, Range range2)

What's the difference between range1 and range2? How am I supposed to know? If it's something where they truly are two generic and interchangeable values, okay, like

public boolean overlap(Range range1, Range range2)

I'd expect that to return true if the ranges overlap and false if they don't, so they are generic and interchangeable.

But if they're different, give me a clue how they are different! I was just working on a program recently that had a "Place" class to hold data about geographical places, and with variables of this type named "p", "place", "place2", "myPlace", etc. Wow, those names really help me determine which is which.

Not the answer you're looking for? Browse other questions tagged or ask your own question.