79

The existing coding standards on a large C# project includes a rule that all type names be fully qualified, forbidding employment of the 'using' directive. So, rather than the familiar:

using System.Collections.Generic;

.... other stuff ....

List<string> myList = new List<string>();

(It's probably no surprise that var also is prohibited.)

I end up with:

System.Collections.Generic.List<string> myList = new System.Collections.Generic.List<string>();

That's a 134% increase in typing, with none of that increase providing useful information. In my view, 100% of the increase is noise (clutter) that actually impedes understanding.

In 30+ years of programming, I've seen such a standard proposed once or twice, but never implemented. The rationale behind it escapes me. The person imposing the standard is not stupid, and I don't think he's malicious. Which leaves misguided as the only other alternative unless I'm missing something.

Have you ever heard of such a standard being imposed? If so, what was the reason behind it? Can you think of arguments other than "it's stupid," or "everybody else employs using" that might convince this person to remove this prohibition?

Reasoning

The reasons for this prohibition were:

  1. It's cumbersome to hover the mouse over the name to get the fully qualified type. It's better to always have the fully qualified type visible all the time.
  2. Emailed code snippets don't have the fully qualified name, and therefore can be difficult to understand.
  3. When viewing or editing the code outside of Visual Studio (Notepad++, for example), it's impossible to get the fully qualified type name.

My contention is that all three cases are rare, and that making everybody pay the price of cluttered and less-understandable code just to accommodate a few rare cases is misguided.

Potential namespace conflict issues, which I expected to be the primary concern, weren't even mentioned. That's especially surprising because we have a namespace, MyCompany.MyProject.Core, which is an especially bad idea. I learned long ago that naming anything System or Core in C# is a quick path to insanity.

As others have pointed out, namespace conflicts are easily handled by refactoring, namespace aliases, or partial qualification.

3

5 Answers 5

76

The broader question:

Have you ever heard of such a standard being imposed? If so, what was the reason behind it?

Yes, I've heard of this, and using fully qualified object names prevents name collisions. Though rare, when they happen, they can be exceptionally thorny to figure out.


An Example: That type of a scenario is probably better explained with an example.

Let's say we have two Lists<T> belonging to two separate projects.

System.Collections.Generic.List<T>
MyCorp.CustomCollections.Optimized.List<T>

When we use the fully qualified object name, it's clear as to which List<T> is being used. That clarity obviously comes at the cost of verbosity.

And you might be arguing, "Wait! No one would ever use two lists like that!" Which is where I'll point out the maintenance scenario.

You've written module Foo for your corporation which uses the corporation approved, optimized List<T>.

using MyCorp.CustomCollections.Optimized;

public class Foo {
    List<object> myList = ...;
}

Later on, a new developer decides to extend the work you've been doing. Not being aware of the company's standards, they update the using block:

using MyCorp.CustomCollections.Optimized;
using System.Collections.Generic;

And you can see how things go bad in a hurry.

It should be trivial to point out that you could have two proprietary classes of the same name but in different namespaces within the same project. So it's not just a concern about colliding with .NET Framework supplied classes.

MyCorp.WeightsAndLengths.Measurement();
MyCorp.TimeAndSpace.Measurement();

The reality:
Now, is this likely to occur in most projects? No, not really. But when you're working on a large project with a lot of inputs, you do your best to minimize the chances of things exploding on you.

Large projects with multiple contributing teams are a special kind of beast in the application world. Rules that seem unreasonable for other projects become more pertinent due to the input streams to the project and the likelihood that those contributing haven't read the project's guidelines.

This can also occur when two large projects are merged together. If both projects had similarly named classes, then you'll see collisions when you start referencing from one project to the other. And the projects may be too large to refactor or management won't approve the expense to fund the time spent on refactoring.


Alternatives:
While you didn't ask, it's worth pointing out that this is not a great solution to the problem. It's not a good idea to be creating classes that will collide without their namespace declarations.

List<T>, in particular, ought to be treated as a reserved word and not used as the name for your classes.

Likewise, individual namespaces within the project should strive to have unique class names. Having to try and recall which namespace's Foo() you're working with is mental overhead that is best avoided. Said another way: having MyCorp.Bar.Foo() and MyCorp.Baz.Foo() is going to trip your developers up and best avoided.

If nothing else, you can use partial namespaces in order to resolve the ambiguity. For example, if you absolutely can't rename either Foo() class you could use their partial namespaces:

Bar.Foo() 
Baz.Foo()

Specific reasons for your current project:

You updated your question with the specific reasons you were given for your current project following that standard. Let's take a look at them and really digress down the bunny trail.

It's cumbersome to hover the mouse over the name to get the fully qualified type. It's better to always have the fully qualified type visible all the time.

"Cumbersome?" Um, no. Annoying perhaps. Moving a few ounces of plastic in order to shift an on-screen pointer is not cumbersome. But I digress.

This line of reasoning seems more like a cover-up than anything else. Offhand, I'd guess that the classes within the application are weakly named and you have to rely upon the namespace in order to glean the appropriate amount of semantic information surrounding the class name.

This is not a valid justification for fully qualified class names, perhaps it's a valid justification for using partially qualified class names.

Emailed code snippets don't have the fully qualified name, and therefore can be difficult to understand.

This (continued?) line of reasoning reinforces my suspicion that classes are currently poorly named. Again, having poor class names is not a good justification for requiring everything to use a fully qualified class name. If the class name is difficult to understand, there's a lot more wrong than what fully qualified class names can fix.

When viewing or editing the code outside of Visual Studio (Notepad++, for example), it's impossible to get the fully qualified type name.

Of all the reasons, this one nearly made me spit out my drink. But again, I digress.

I'm left wondering why is the team frequently editing or viewing code outside of Visual Studio? And now we're looking at a justification that's pretty well orthogonal to what namespaces are meant to provide. This is a tooling backed argument whereas namespaces are there to provide organizational structure to the code.

It sounds like the project you own suffers from poor naming conventions along with developers who aren't taking advantage of what the tooling can provide for them. And rather than resolve those actual issues, they attempt to slap a band-aid over one of the symptoms and are requiring fully qualified class names. I think it's safe to categorize this as a misguided approach.

Given that there are poorly named classes, and assuming you can't refactor, the correct answer is to use the Visual Studio IDE to its full advantage. Possibly consider adding in a plugin like the VS PowerTools package. Then, when I'm looking at AtrociouslyNamedClass() I can click on the class name, press F12 and be taken directly to the definition of the class in order to better understand what it's trying to do. Likewise, I can press Shift-F12 to find all the spots in the code currently suffering from having to use AtrociouslyNamedClass().

Regarding the outside tooling concerns - the best thing to do is to just stop it. Don't email snippets back and forth if they aren't immediately clear what they refer to. Don't use other tools outside of Visual Studio as those tools don't have the intelligence surrounding the code that your team needs. Notepad++ is an awesome tool, but it's not cut out for this task.

So I agree with your assessment regarding the three specific justifications you were presented with. That said, what I think you were told was "We have underlying issues on this project that can't / won't address and this is how we 'fixed' them." And that obviously speaks to deeper issues within the team that may serve as red flags for you.

12
  • 1
    +1. I've also actually encountered some nasty collisions in our internal namespaces. Both in porting legacy code to a "2.0" project, and just with a select few class names that are semantically valid in different namespace contexts. The really tricksy thing is that two things with the same name will often have similar interfaces, so the compiler won't complain ... your runtime will!
    – svidgen
    Commented Oct 8, 2015 at 15:01
  • 27
    This problem is solved through using namespace aliases, not by imposing silly rules requiring code by cluttered with explicit namespace usage.
    – David Arno
    Commented Oct 8, 2015 at 15:04
  • 4
    @DavidArno - I don't disagree with you. However, large projects may not have that option. I'm merely pointing out why a large project may impose that rule. I'm not advocating for the rule, though. Just that it's sometimes required because the team doesn't have any other options.
    – user53019
    Commented Oct 8, 2015 at 15:05
  • 4
    @GlenH7 you might want to specify the other available solutions in your answer. I'd hate to see people stumble across this and think "Oh. That's a great idea!" +1 for remaining objective and pragmatic though.
    – RubberDuck
    Commented Oct 8, 2015 at 15:09
  • 3
    @JimMischel - It sounds like the rule is being used as a crutch for something. It may not be possible to determine what that thing is though. At a high level, yes, there is sometimes justification for not allowing usings but it doesn't sound like your project qualifies as one of those cases.
    – user53019
    Commented Oct 8, 2015 at 18:03
20

I did work at one company where they had many classes with the same name, but in different class libraries.

For example,

  • Domain.Customer
  • Legacy.Customer
  • ServiceX.Customer
  • ViewModel.Customer
  • Database.Customer

Bad design, you might say, but you know how these things develop organically, and what's the alternative - rename all the classes to include the namespace? Major refactoring of everything?

In any case, there were several places where projects which referenced all these different libraries needed to use multiple versions of the class.

With the using directly at the top, this was a major pain in the arse, ReSharper would do odd things to try and make it work, rewriting the using directives on the fly, you would get Customer-can't-be-cast-as-Customer-style errors and not know which type was the correct one.

So, having at least the partial namespace,

var cust = new Domain.Customer

or

public void Purchase(ViewModel.Customer customer)

greatly improved the readability of the code and made it explicit which object you wanted.

It wasn't a coding standard, it wasn't the full namespace, and it wasn't applied to all classes as standard.

12
  • 14
    "whats the alternative, rename all the classes to include the namespace? major refactoring of everything?" Yes, that's the (correct) alternative.
    – David Arno
    Commented Oct 8, 2015 at 15:04
  • 2
    Only in the short-term. It's far less expensive than using explicit namespaces in code in the long term.
    – David Arno
    Commented Oct 8, 2015 at 15:07
  • 4
    Happy to accept that argument, as long as you are paying me in cash not shares.
    – Ewan
    Commented Oct 8, 2015 at 15:10
  • 9
    @David: No, it's NOT the correct alternative. Fully qualifying either all identifiers or at least those which actually collide is the correct way and the reason why namespaces exist in the first place is to provide collisions when the same name is used in different modules. The point is that some of the modules may be from 3rd parties, which codebase you can't modify. So what do you do, when identifiers from two different 3rd party libaries collide and you need to use both libraries, but can't refactor either of them? Namespaces exist, because refactoring is not always possible.
    – Kaiserludi
    Commented Oct 9, 2015 at 10:35
  • 4
    @CarlSixsmith, if one subscribes to Martin Fowler's views on refactoring, then if the change impacts the user, then you are correct, it's not refactoring; it's another form of restructuring. This raises two points though: 1. are all public methods automatically part of the API? 2. Fowler himself acknowledges he's fighting a losing battle over this definition, with a growing number of people using the term "refactoring" to mean generalised restructuring, including public changes.
    – David Arno
    Commented Oct 9, 2015 at 20:22
8

There is no good to be too verbose or too short: one should find a golden middle in being detailed enough in order to prevent subtle bugs, while avoiding to write too much code.

In C#, an example of that are the names of arguments. I encountered several times a problem where I spent hours looking for a solution, while a more verbose style of writing could prevent the bug in the first place. The problem consists of an error in the order of the arguments. For instance, does it look right to you?

if (...) throw new ArgumentNullException("name", "The name should be specified.");
if (...) throw new ArgumentException("name", "The name contains forbidden characters.");

At the first sight, it looks perfectly fine, but there is a bug. The signatures of the exceptions' constructors are:

public ArgumentException(string message, string paramName)
public ArgumentNullException(string paramName, string message)

Noticed the order of arguments?

By adopting a more verbose style where the name of an argument is specified every time the method accepts two or more arguments of the same type, we prevent the error from happening again, and so:

if (...) throw new ArgumentNullException(paramName: "name", message: "The name should be specified.");
if (...) throw new ArgumentException(paramName: "name", message: "The name contains forbidden characters.");

is obviously longer to write, but results in less time wasted debugging.

Pushed to extremes, one could force to use named arguments everywhere, including in methods such as doSomething(int, string) where there is no way to mix the order of the parameters. This will probably harm the project in long term, resulting in much more code without the benefit of preventing the bug I described above.

In your case, the motivation behind the “No using” rule is that it should make it more difficult to use the wrong type, such as MyCompany.Something.List<T> vs. System.Collections.Generic.List<T>.

Personally, I would avoid such rule because, IMHO, the cost of difficult to read code is much above the benefit of a slightly reduced risk of misusing the wrong type, but at least, there is a valid reason for this rule.

3
  • Situations like these can be detected by tools. ReSharper marks the paramName with the InvokerParameterName attribute and issues a warning if no such parameter exist.
    – Johnbot
    Commented Oct 9, 2015 at 9:08
  • 2
    @Johnbot: they certainly can, but in a very limited number of cases. What if I have a SomeBusiness.Something.DoStuff(string name, string description)? No tool is smart enough to understand what is a name and what is a description. Commented Oct 9, 2015 at 12:04
  • @ArseniMourzenko in this case even human needs to take time figuring out if the invocation is correct or not.
    – Gqqnbig
    Commented Mar 15, 2017 at 1:43
8

Namespaces gives code a hierarchical structure, allowing for shorter names.

   MyCompany.Headquarters.Team.Leader
   MyCompany.Warehouse.Team.Leader

If you allow the "using" keyword, there is a chain of events...

  • Everyone is really using one global namespace
    (because they include every namespace they could possibly want)
  • People start to get name clashes, or
  • worry about getting name clashes.

So to avoid the risk, everyone starts using really long names:

   HeadquartersTeamLeader
   WarehouseTeamLeader

The situation escalates...

  • Someone else may already have chosen a name, so you use a longer one.
  • Names get longer and longer.
  • Lengths can exceed 60 characters, with no maximum - it gets ridiculous.

I have seen this happen, so can sympathize with companies which ban "using".

1
  • 13
    Banning using is the nuclear option. Namespace aliases and partial qualification are preferable. Commented Oct 8, 2015 at 16:40
2

The problem with using is that it magically adds to the namespace without an explicit declaration. This is much more of a problem for the maintenance programmer who encounters something like List<> and without being familiar with the domain, does not know which using clause has introduced it.

A similar problem occurs in Java if one writes import Java.util.*; rather than import Java.util.List; for example; the latter declaration documents what name has been introduced so that when List<> occurs later in the source, its origin is known from the import declaration.

3
  • 6
    Whereas it's true that somebody unfamiliar with the domain will have some difficulty, all he has to do is hover the mouse over the type name and he'll get the fully qualified name. Or he can right-click and go directly to the type definition. For .NET Framework types, he probably already knows where things are. For domain-specific types, it'll take him perhaps a week to become comfortable. At that point, the fully qualified names are just noise that impedes understanding. Commented Oct 9, 2015 at 13:39
  • Jim .. I just tried hovering my mouse over a definition and it didn't work. Had you considered the possibility that some programmers in the world don't use Microsoft IDEs ? In any case, your counter does not invalidate my point, that the source with using is no longer self-documenting Commented Oct 15, 2015 at 22:01
  • 2
    Yes, there are people working in C# who are handicapping themselves by not using the best available tools. And, whereas the argument that full qualification is "self documenting" has some merit, such code has a huge cost in readability. All that extraneous code creates noise that obscures the parts of the code that really matter. Commented Oct 16, 2015 at 15:04

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