Var Wars
A long time ago in a company far far away…
There was a team that still forbade the use of var entirely. It seemed strange to me and I couldn’t understand why. So let’s discuss a few different example and see if it makes sense.
First, we’ll tackle anonymous types—the only place where var haters and lovers come to an agreement.
public void ObiVarKenobi()
{
var anonymousGreenGuy = new
{
Name = "Yoda",
Age = 900,
Quote = "Fear of vars is the path to the dark side. Fear leads to anger. Anger leads to hate. Hate leads to suffering."
};
var tenPorkinsLikePilots = Enumerable.Range(0, 10).Select(i => new { Name = "Porkins", Weight = 170 });
}
The reason why is that the use of the var is mandatory with anonymous types. There is no other option, therefore some teams ban the use of them as well.
One of the most common arguments against var usage is the lack of knowledge of the type without a proper IDE. So, let’s continue with the use cases where the type is instantly visible from the right side.
public void Varbacca()
{
var pilots = new List<IPilot>();
var pilotWeights = new Dictionary<IPilot, double>();
var pilot = (IPilot)GetUndefinedFatObjectThatCanFly();
var porkins = Porkins.Instance;
var castedPorkins = porkins as Porkins;
var generatedMassOfPorkins = Enumerable.Range(0, 10).Select(i => Porkins.Instance).Cast<IPilot>();
}
public void Chewbacca()
{
List<IPilot> pilots = new List<IPilot>();
Dictionary<IPilot, double> pilotWeights = new Dictionary<IPilot, double>();
IPilot pilot = (IPilot)GetUndefinedFatObjectThatCanFly();
Porkins porkins = Porkins.Instance;
Porkins castedPorkins = porkins as Porkins;
IEnumerable<IPilot> generatedMassOfPorkins = Enumerable.Range(0, 10).Select(i => Porkins.Instance).Cast<IPilot>();
}
Hmm…it looks like Chewbacca is repeating himself a lot and it looks like var has just earned couple points. The amount of a code noise is reduced a lot. If you start with this simple rule you will notice that you will read the code in a slightly different way, but don’t be scared of it. It’s a change that you will only benefit from.
After that example, it’s becoming a little more functional and the LINQ usage and short methods play the main part in the next example.
public void VarSolo()
{
var pilotWeights = new[] { 110, 150, 75, 55, 103, 80, 120, 97 };
var alliancePilotWeights = pilotWeights.Where(i => i > 95).ToList();
var shuttleTonnage = alliancePilotWeights.Select(ComputeTonnageFor).Sum();
}
public void HanSolo()
{
int[] pilotWeights = new[] { 110, 150, 75, 55, 103, 80, 120, 97 };
List<int> alliancePilotWeights = pilotWeights.Where(i => i > 95).ToList();
int shuttleTonnage = alliancePilotWeights.Select(ComputeTonnageFor).Sum();
}
Despite “saving” just a few letters, I find this example very important. Using var allows you to focus on the functionality and not the return type itself and it doesn’t matter whether the type is an array of bytes or just an integer. The important thing is written on the right side of the statement and this is the place where you should start looking.
Let’s move on to the next example.
public void LukeSkyvarker()
{
// Long class names
var allicanceShuttle = ConstructShuttle();
// Better local variable naming
var currentPilot = CreateAlliancePilot();
.
.
.
currentPilot.DieInAHorribleWay();
// Enforcing variable initialization with declaration
var porkins = Porkins.Instance;
}
public void LukeSkywalker()
{
// Long class names
BigWhiteRealCosmicSpaceShuttleWithALotOfWeaponsAndHairyBeastOnTheBoard<AlliancePilot> allicanceShuttle = ConstructShuttle();
// Better local variable naming
IPilot current = CreateAlliancePilot();
.
.
.
current.DieInAHorribleWay(); // what could current be?
// Enforcing variable initialization with declaration
IPilot porkins;
.
.
.
porkins = Porkins.Instance;
}
In the first statement, Luke is writing more readable code when he omits very long class name. If you try to argue that you should use reasonably long name, you should of course, but try to succeed with WPF generic view models and Prism.
Luke’s second example shows how the var could enforce better naming. When you have the comfort of a type on the left side, you tend to get sloppy and leave the important part of the information hidden in the type. I am not suggesting using postfixes and prefixes or any kind of weird hungarian notation, but really, don’t use current as an identifier.
In the third part of the sample, you can see how var saves you from a bad habit of delaying initialization. There are some use cases where it’s handy, but most of the time it isn’t.
Coming to the end of the article, we are approaching to the dark side of vars. Those are the place where even I, the var advocate, don’t use them…that often.
public void DarthVader()
{
string name = "Jek Tono Porkins";
int mass = 110;
decimal money = 0.3m;
float moneySpentOnPizza = 130.5f;
double height = 1.8;
bool isPorkinsFat = true;
byte r2d2flag = 0xf;
}
public void VarVader()
{
var name = "Jek Tono Porkins";
var mass = 110;
var money = 0.3m;
var moneySpentOnPizza = 130.5f;
var height = 1.8;
var isPorkinsFat = true;
var r2d2flag = 0xf;
}
In summary, don’t forbid developers to use var. It is one of the very useful features of C# and the main advantages are
- avoiding repetition,
- reducing code noise,
- better naming and
- focus on the function.
As with any other feature, it should be used mindfully and with care and If you are on the other side of this war, please, give var a chance. It would take you a week or two to adapt, but after that, you are going to love it. Promise!