23

I enjoy and highly recommend Juval Lowy's - C# Coding Standard. Juval explicitly avoids rationale for each directive in order to keep the standard tight (see the preface). However, there are a few directives for which I find myself curious as to the rationale.

What is the specific rationale to the following directives from Lowy's C# standard?
Hopefully there are hard (non-subjective) answers to these.

1.13 Avoid fully qualified type names. Use the "using" statement instead.
Is this a performance issue? Sometimes I only need one instance of the fully qualified name and adding a using seems heavy.

1.26 Use empty parenthesis on parameterless-anonymous methods. Omit the parenthesis only if the anonymous method could have been used on any delegate.
Actually I am just confused by the second sentence. Explanation with example(s) would help, thank you.

2.19 Avoid defining custom exception classes
What are the considerations in minimizing their numbers? (He next gives guidelines if you do define them (in 2.20).)

2.29 Avoid using the ternary conditional operator
Too hard for the reader to digest, or other considerations?

2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them.
I don't think I do this, but I am curious...why not?

2.47 Avoid interfaces with one member.
Because it is always/usually more prefereable to do what? One method interfaces work when?

2.53 Prefer using explicit interface implementation
Why? Also, Jon Skeet disagrees here.

Thanks in advance! Robert

Community
  • 1
  • 1
RAL
  • 917
  • 8
  • 19
  • 2
    I think this should be community wiki, as it will be a lot of single answers, and there is no 'correct' answer unless Juval himself pipes up. – DevinB Jun 16 '09 at 19:05
  • I think SO experts might actually "know" the answers. Do I really need to break it up into 7 questions? I keep getting bitten by the community wiki bug, very frustrating. – RAL Jun 16 '09 at 19:10
  • Re: 7 questions. I'd say yes. Thus far no one has responded to all points and, frankly, why I haven't chimed in. – Colin Burnett Jun 16 '09 at 19:11
  • @devinb - my last question was deemed too subjective and got moved to CW and closed. The wildly popular questions on SO are almost all subjective, I understand why they go to CW, but the fact that they are so wildly popular makes me wonder how connected the community is with those that seem to police/enforce it. I know this has probably been hashed out ad nauseum, but I hadn't noticed it before recently. – RAL Jun 16 '09 at 19:22
  • But this IS a CW question. Making it community wiki doesn't mean it will be closed. This question cannot be answered succinctly, because you have asked 7 distinct and separate questions. – DevinB Jun 16 '09 at 19:25
  • How do you mark the "Correct" answer? What if they got 4 of 7 correct? What if someone absolutely nailed it on 1 of them, and didn't answer the rest? – DevinB Jun 16 '09 at 19:26
  • 2
    @devinb - I guess this is how I learn. I thought there was more value to keeping them all in one place because...well, because they all came from one place and I thought it would look weird to repeat the pre-amble to the question for each one. I do see now how it is harder for me to choose one of them as the correct answer...my bad! – RAL Jun 16 '09 at 19:30
  • 1
    You are correct to put them all in one place. But that's when you mark the question as CW. – DevinB Jun 16 '09 at 19:38
  • 1
    Having seen Juval speak (TechEd a few years ago), he does come over as rather pedantic, but does have his reasons to simplify usage. This does not mean I agree, and the guidelines in the "Framework Design Guidelines" are both more comprehensive and (IMO) better. – Richard Jun 17 '09 at 07:21

8 Answers8

10

2.29 Avoid using the ternary conditional operator I have no problems with "simple" uses of the ternary operator but have recommended against using it in a nested fashion:

// This is fine
x := (conditionA) ? true_resultA : false_resultA;

// This would probably be clearer using if-then-elseif
x := (conditionA) ? 
       ((conditionA1) ? true_resultA1 : (condition2) ? true_result2 : false_result2) :
       ((conditionA2) ? true_resultA2 : false_resultA2);
Mark
  • 1,763
  • 1
  • 12
  • 6
  • 3
    This is the same conclusion I've always came to regarding this. Simple uses of the ternary operator are fine, but don't abuse it with excessive conditions or nesting. – Ryan Versaw Jun 16 '09 at 20:00
  • agreed. usages for copying object data i think are the most useful and contribute positively for readability. When you have a series of property = value; lines. having a block of if/else becomes negative to the readability. – JDPeckham Feb 27 '11 at 16:30
9

Obviously, I'm not Juval, but I can take a stab at these

1.13 Avoid fully qualified type names. Use the "using" statement instead.

Performance can't be the issue here. I'm sure the issue is readability.

1.26 Use empty parenthesis on parameterless-anonymous methods. Omit the parenthesis only if the anonymous method could have been used on any delegate.

public delegate void Foo1();
public delegate void Foo2(int val);

public void Foo()
{
    Foo1 first = delegate { Console.WriteLine("Hello world"); };
    Foo2 second = delegate { Console.WriteLine("Hello world"); };
    Foo1 third = delegate() { Console.WriteLine("Hello world"); };
    Foo2 fourth = delegate() { Console.WriteLine("Hello world"); }; // does not compile
}

Without the parens, the anonymous delegate can be applied to any delegate. With the parens, you're being specific about the signature of the delegate. Prefer the second syntax unless you really need the flexibility.

2.19 Avoid defining custom exception classes

Again, readability is the issue here. The framework exception classes are rich and well-understood. Be wary when replacing them.

2.29 Avoid using the ternary conditional operator

It's a readability and expandability thing. I don't really agree, but it's a standard religious fight.

2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them.

Partially this is readability, and partially it's for ease of debugging. I've starting to assign almost everything to temporary variables just so that they're easily found in the debugger later on.

2.47 Avoid interfaces with one member.

"Avoid" is kinda like "prefer", he's just saying think twice before you do it. If you only have one member, is the interface really modeling something useful and complete in your design? It's pretty rare to have a class with just one member, think seriously about why your interface is any different.

2.53 Prefer using explicit interface implementation

This is similar to the idea of using the least-public accessor you can. If your class doesn't need to make the interface public, then it probably shouldn't. This is going to differ significantly based on your design, obviously, but given the fact that most people just make the interface implicit without really thinking about it, it's advice worth considering.

tnyfst
  • 1,601
  • 1
  • 10
  • 9
  • 3
    2.47 Avoid interfaces with one member. Interesting... i've always heard (and benefitted in practice via unit tests/mocks) narrow interfaces are better. Wouldn't 1 method be the most narrow interface in that scenario? Single Responsibility Principle... each object should do 1 thing. therefore 1 method or multiple variations on that method (overloads) are best. Overloads would be the only reason to have more than 1 interface method in that case, right? (Citations: Clean Code, Agile Principles Patterns and Practices in c#, Architecting Applications for the enterprise, Test-Drive Development). – JDPeckham Feb 27 '11 at 16:21
5

1.26 is about pre-lambda delegate { } syntax.

// #1 Empty parenthesis on parameterless-anonymous methods would be:
delegate() { }
// #2 ... anonymous method could have been used on any delegate, is:
delegate { }

Remember, the latter can be assigned to any delegate, regardless of its parameters. The delegate just ignores these using some compiler trickery.

If you define a delegate taking no parameters, explicitly say so using #1. Don't "leave the parenthesis out because your delegate doesn't take any parameters anyway".

Jabe
  • 1,491
  • 1
  • 12
  • 14
4

A lot of these guidelines speak to the "quality attributes" of good software design (i.e. maintainability, reliability, reusability, testability, expandability, debugability, interoperability, and what other -ilities you can name).

Often people create code that works fine at the time but may not be the best choice when considering all the quality attributes (in the sense of "where can this software go in the future" or "someone else has to use this code, too").

For example:

2.29 Avoid using the ternary conditional operator

I have no problem with ternary expressions, per se, but by writing code such as: int result = CheckMethod() ? OnTrueDoThis() : OnFalseDoThat()... you are saying, "I have a conditional that, if true (or false), you can do one and only one thing." The whole construct discourages expandability. You have to recreate the construct (with an if..else statement).

Similarly...

2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them.

You called a function and essentially "discarded" the results for later use. If that information is needed later, either the function would have to be called again or the structure of the code would have to be rewritten. It would also make checking or logging the results (for future debugging) more difficult.

halfer
  • 19,824
  • 17
  • 99
  • 186
Robert Cartaino
  • 27,494
  • 6
  • 45
  • 67
  • 1
    2.29: The conditional operator is easy to misuse, but sometimes convenient. I wouldn't hesitate to use it where appropriate. 2.31: The rationale you gave looks like a classic case for applying YAGNI. – David Thornley Jun 16 '09 at 20:15
  • i think robert was agreeing with 2.31 and providing more info on why. now you have a local with the data instead of discarding it in the conditional evaluation. – JDPeckham Feb 27 '11 at 16:41
4

Regarding 1.13 (Avoid fully qualified type names. Use the "using" statement instead):

It may be a bit more than readability. If you have too many usings at the beginning of the file, you have a class that is coupled with classes from too many namespaces.

The class is screaming out for refactoring. Using usings instead of fully-qualified class names lets you identify such tightly-coupled classes more easily.

azheglov
  • 5,475
  • 1
  • 22
  • 29
3

This is my best stab at the questions you've listed. For the ones that I can't really say, I've omitted.

1.13 Avoid fully qualified type names. Use the "using" statement instead.

Readability. It's must harder to read code when you have to read fully qualified type names.

2.19 Avoid defining custom exception classes

The .NET framework comes with a good set of exceptions built into the system. Unless the exception you're modeling is business domain specific, you'll probably be able to use one of the existing exception classes.

2.29 Avoid using the ternary conditional operator

I think this is most likely because he thinks people may not understand the operator, but I disagree.

2.47 Avoid interfaces with one member.

He might be warning people of building interfaces that are too thin. However, I would actual say the converse, warning people of making interfaces too verbose. If you've ever had to deal with ASP.NET MembershipProvider, you know what I'm talking about.

2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them.

A couple of reasons I can think of here. Readability. It can make conditional statements hard to understand if you are making function calls in them. Also, it's harder to debug if you're not watching.

2.53 Prefer using explicit interface implementation

I believe his reasoning here is to for brevity. However, I don't actually agree with this assessment. I think Jon is correct, implicit interface should be used when you can, and explicit when appropriate.

Joseph
  • 25,330
  • 8
  • 76
  • 125
  • 1.13 - Sometimes I find the fully qualified name useful because I wasn't sure where that method lived and now I don't have to stop reading just to look it up. Assuming it isn't overdone. – RAL Jun 16 '09 at 19:37
  • @Robert That can be true at times, but I think those are Exception and not the Rule. – Joseph Jun 16 '09 at 19:41
  • 1
    Company.Package.I Company.Package.personally Company.Package.hate Company.Package.when Company.Package.people Company.Package.do Company.Package.this. – JDPeckham Feb 27 '11 at 16:33
2

Here are some of my reactions of which I dare answer them :)

1.13 Avoid fully qualified type names. Use the "using" statement instead. I disagree. It's certainly not performance related. It can lead to improved readability to have var foo = new Foo() instead var foo = new MyCompany.MyNamespace.Helpers.Xml.Foo() but other than that - no.

2.19 Avoid defining custom exception classes This is nonsense imho. You should avoid creating custom exceptions that derive from ApplicationException, but there is nothing wrong with custom exceptions (as long as you're not going to reinvent existing exceptions that is).

2.29 Avoid using the ternary conditional operator I have no idea why that would be a guideline. I have read that not all people use it and may not recognize it, but that is not a valid reason to not use a useful operator.

2.31 Avoid function calls in Boolean conditional statements. Assign into local variables and check on them. This is simply a readability issue in my opinion.

2.47 Avoid interfaces with one member. I also disagree here. You should avoid 'marker' interfaces though - interfaces with no marker, but who just serve the purpose that something is '...ble'. But, one method on an interface seems fine to me.

Razzie
  • 30,834
  • 11
  • 63
  • 78
  • Agree on 2.19: guidance should be: avoid reinventing framework exception classes. – Richard Jun 17 '09 at 07:19
  • 1.13 Avoid fully qualified type names. Use the "using" statement instead: Does it make any difference to the linker when using Link All in Xamarin.Forms in terms of binary size? – Amir Hajiha Apr 17 '19 at 11:04
0

2.29 Ternary operator

To start with, if you start to use the ternary operator, there should be a reason for the use of the ternary operator over a regular if-then-else. Observe :

if (x == 0) {...} else{...} //A set of statements demand a regular If-then-else

//A simple assignment can be handled by the ternary operator
y = (x == 0)? 1 : 0 //this is readable and how it should be used


(x==0)? callSomething() : callSomethingElse() //this is NOT how it should be used

The ternary statement is meant for returning one of two values depending upon the conditional it is evaluating. This is extremely handy when doing FP. For call statements that do not return a value, you should revert to if-then-else.

Arnab Datta
  • 5,356
  • 10
  • 41
  • 67