23

I know the title of the question is very subjective, but I was confronted with usage of ?? operator by my peers, where at the same time I was not very happy/comfortable with applying var in new up-coming code.

The argument given for using ?? operator was, it takes away readability in code.

My question is, doesn't the same thing happens when you start using var?

8
  • 49
    If a "developer" can't understand the ?? null coalesce operator after it's explained, they shouldn't be allowed near production code.
    – CaffGeek
    Mar 16, 2011 at 20:47
  • 12
    I suggest we change the operator from ?? to IfNullThen. ? can be IfSoChoose, : is ElseChoose. + is Add. - is Subtract, unless it's unary, then it's Negative. -- is split between DecrementBeforeUsing, and DecrementAfterUsing. In C++ you can do this with macros. Nov 9, 2011 at 15:07
  • 7
    @Xaade: That's irony isn't it? ... right? ... god let it be irony (and I'm an atheist). Nov 9, 2011 at 21:21
  • 10
    @StevenJeuris It might be sarcasm, but it's not irony. Nov 10, 2011 at 2:51
  • 1
    @KirkBroadhurst: I stand corrected, have always been confusing those two. Nov 10, 2011 at 9:49

7 Answers 7

53

Null coalescing operator (??)

Personally, I don't see any downsides to using this operator. Consider the following three code samples, from 'easy' to 'complex' new operators.

Without magic:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

Ternary operator:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

Null coalescing:

string name = null;
Console.WriteLine( name ?? "No name set." );

The reason these operators were invented is because they represent very common programming operations. Not wanting to use them because you aren't used to them is just being stubborn. Languages evolve, features evolve, learn to use them!

var keyword

I have a somewhat different opinion about the var keyword. The type of a variable often gives extra information about your code. I find hiding the type by using the var keyword sometimes makes code less readable. You know less what to expect without using auto completion, or hovering over the identifiers to see what they actually are. In my opinion, this results in code which is slower to read/write.

I do use the keyword when I find that the type doesn't give much extra information.

  • Mainly in foreach loops, which I learned from Resharper as it is a setting there. Most of the time, you know what type of collection you are traversing, so you know you are expecting items from within that collection.
  • Linq queries. The result of linq queries are often very complex generic types. Displaying this type does more harm than good.
  • Long typenames which are simply initialized with their constructor. You can already tell what the type is by looking at the constructor.

As an example for the last statement:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();
17
  • 24
    That last example is exactly when the var keyword can excel. Imagine that code is littered throughout your code. Factory.CreateSomeType returns IEnumerable<SomeType>. One day, for whatever reason, it changes to return SomeType[]. If you've used var, it's just a recompile.
    – pdr
    Mar 16, 2011 at 13:06
  • 1
    Got that example the wrong way around and then went to find food. Numpty! A better example would be using yours. What if Factory.CreateSomeType() changes to return an ISomeType?
    – pdr
    Mar 16, 2011 at 13:27
  • 5
    @pdr: That most likely means the interface changed as well, and behavior needs to be adjusted/added as well. If it's a simple rename you ofcourse have automated renaming. If the 'contract' changes, I rather see my code breaking so I can see whether I have to adjust something or not. Mar 16, 2011 at 13:36
  • 2
    I think it's much more likely that if returning a concrete type becomes returning an interface that it is just allowing for other concrete types with the same interface (consistent with the Factory pattern). But if the contract does change then your code will break - though you may find it only breaks in a few cases where it matters rather than everywhere.
    – pdr
    Mar 16, 2011 at 13:46
  • 1
    @Tom Hawtin, we all know it's inevitable to avoid null entirely. Furthermore, the more I look for alternatives for null, the more I realize using null is sometimes the cleanest solution. My given example isn't all that bad IMHO, and I find it an appropriate usage of nullable types. Mar 16, 2011 at 14:16
16

var allows less verbose code, which increases readability. In my opinion, readability should not be measured by how many details you see, but how many details are hidden at the first glance. Besides Linq examples, var allows duck typing at source code level, given the following example:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

Who cares what is the type of label as long as it provide the Text property?

5
  • Someone trying to understand whether this is e.g. a winforms label or a WPF label. Mar 16, 2011 at 14:45
  • 14
    @Steven Jeuris: that's usually a known context information. If not, you are approaching the code in a wrong way.
    – Codism
    Mar 16, 2011 at 14:58
  • Someone who wants to know whether it is a default WPF label or some custom label then? :) Nov 9, 2011 at 21:24
  • 14
    1. Should that person really care, so long as it's a label with a Text property? 2. If this is one of the rare cases that they REALLY DO have a good reason to care, ask Intellisense. 3. If they're editing code in an IDE without Intellisense, they probably have way bigger inconveniences than 'var' :)
    – KutuluMike
    Nov 10, 2011 at 20:12
  • 4
    Someone with a poor sense of abstraction.
    – Jim Balter
    May 10, 2013 at 18:39
16

I don't have any serious comments on the ?? operator, as I've never used a language with such an operator heavily. Regarding var, people program in languages like Ruby, Python, Perl and PHP that have fully implicit typing all the time. Natives of these languages realize that the formal type of a variable is usually irrelevant noise. You're more interested in what the variable can do, i.e. its structural/duck interface.

Similarly, I program mostly in D. D is statically typed but has the auto keyword, which is equivalent to var. It's considered idiomatic to use it everywhere unless you see a specific need to emphasize the type of something to either the reader or (via implicit conversion) the compiler. Except occasionally when used as a function return type (this is allowed in D), I've never found it to hamper readability, because I mostly think in terms of structural/duck interfaces, not formal/nominative types, when I program.

Furthermore, IMHO using var everywhere possible is a good example of DRY. The type of something should be specified in one and only one place, and then automatically be propagated whenever it needs to be propagated. If you use var and the formal type of the variable needs to change at some point, the necessary changes will automatically be propagated everywhere necessary by the compiler as long as the program is still type-correct, rather than the programmer having to manually change every instance. This is a Good Thing (TM).

13

I think this is a question for the team in the end. If it's not readable to anyone else on my team then I won't use it, although I might try a couple of times to convince them with examples, or by pointing out analagous abbreviations (such as +=) which they find more readable.

However, if working alone then I find ?? and var emminently readable with no limits. Even

var a = b ?? c ?? d ?? e ?? "";

is pretty unambiguous to me.

Ternary operators and dynamic are a different matter, of course.

7
  • 5
    I would use `String.Empty' here.
    – Job
    Mar 16, 2011 at 20:04
  • 1
    @Job, in honesty, so would I. I was going to put something in that string, then couldn't think of anything :)
    – pdr
    Mar 16, 2011 at 20:13
  • 4
    var a = b ?? c ?? d ?? e ?? String.Empty ?? ""; Nov 9, 2011 at 15:09
  • 2
    @Xaade You can never be sure enough. But really, using String.Empty or "" is a personal preference. I use "" because it's shorter...
    – Carra
    Nov 10, 2011 at 14:19
  • 13
    @Xaade - if String.Empty ever returns null, we're in for one hell of a lot of broken code. Nov 10, 2011 at 18:29
10

The argument given for using ?? operator was, it takes away readability in code.

Briefly thinking about it, this comment tells me the person making the comment, doesn't understand it as well as he/she should. It is most likely true in certain situations, but on the whole, I don't discount something that the C# team obviously thought was important enough to add because of "readability". I put this in the same category of if(boolean_object) vs if(boolean_object == true). Some people argue that the second is more readable, but in reality it's just adding extra code for someone to read/type, and in some situations can be more confusing (think if(boolean_object != false))

My question is, doesn't the same thing happens when you start using var?

The C# team has allowed you to not define something which you know what it is going to be. Unless I absolutely need to define what a variable is going to be (either it is absolutely important that a returning object is of type x, or it really isn't readable), I use var. var x = "MY_STRING"; I know it's a string from looking at it. In truth, I don't really care that it's a string as long as it does what I need it to do. Defining the variable type is for my benefit, not the compiler's. If something is wrong, the compiler will tell me when it runs if I have the wrong variable type.

0

The var keyword is, in my opinion, bested used in the situations for which it was original introduced--LINQ queries. In these queries, the type of the returned result often has some big convoluted name that is difficult to determine ahead of time and doesn't aid the reader's understanding of what your code does.

However, doing var text = "Some text " + variableName + "some more text." is just lazy.

EDIT: @Jorg You jumped on a purposefully simplistic answer but added nothing to the discussion. OK, how about this for a better example: var items = doc.DocumentElement.FirstChild.ChildNodes; If you can figure out the type from that I'll give you a cookie.

10
  • 18
    If you can't figure out that "Some text " is a string, then you have much bigger problems to worry about than the number of vars in your code. Mar 16, 2011 at 16:26
  • 3
    The problem isn't var; the problem is the crappy variable name "items". If you use a good variable name, there's nothing wrong with var.
    – Kyralessa
    Nov 10, 2011 at 18:30
  • 3
    I'm guessing (without looking) that items is a collection of XML nodes, which I expect to have all of the properties and methods of a collection of XML nodes, and that's really all I need to know.
    – KutuluMike
    Nov 10, 2011 at 20:16
  • If you need to know what type the var stands for and can't tell immediately by looking, just hover the mouse over it. Doesn't take much figuring out to do it.
    – scrwtp
    Dec 1, 2011 at 1:11
  • 1
    "is just lazy" -- This isn't an argument against it. In fact, it isn't at all intelligent.
    – Jim Balter
    May 10, 2013 at 18:44
0

I have a fundamental issue with using var.

In this example everything is side-by-side, but the issue is really with large solutions with shared libraries or projects.

Consider this:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

What happens if GetMeAnObject is changed, by someone else, to suit their needs?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

The MainProgram method will have a big red error on .PerformOperation(). What happened? PerformOperation worked perfectly well before. We look at the methods on theObject and it's just disappeared without a trace. It was there last time, and we need that method. You could spend a long time chasing your tail and trying to figure out why, if MyFirstObject has a method called PerformOperation, it now can't be seen. Everybody "knows" that GetMeAnObject returns a MyFirstObject, so there's no point checking that.

If you had explicitly typed theObject then you would have an Invalid Cast error on the line that calls GetMeAnObject, and it would be blindingly obvious that GetMeAnObject is returning a type that is not what you expect.

In short, explicit declaration means you know what the errors mean. An invalid cast means you expected one type and another type was returned. An unrecognised member means the member was unrecognised.

2
  • 11
    A co-worker made a breaking change in code not covered by tests, and you think the problem is var? The language cannot be expected to protect against that sort of behaviour--what if they'd modified MyFirstObject directly? It would still have broken, but no syntax could have saved you from that. I'd consider this a strength of var, even: what if instead of returning MySecondObject you were now returning IMyFirstObject instead?
    – Phoshi
    Aug 15, 2012 at 11:31
  • 2
    "Everybody "knows" that GetMeAnObject returns a MyFirstObject, so there's no point checking that." I can't actually think of a scenario in programming where I would actually depend on my memory of what GetMeAnObject if I am debugging. If I checked that PerformOperation is not there, I would have seen the code and no it is for another class. If in an IDE the class would pop up the instance I look at the type of the object. Actually, when the compiler tells me the error, it would say 'class MySecondObject has no operation PerformOperation'. How is that for everybody knows? Aug 15, 2012 at 13:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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