2

When learning C# (and OO concepts more generally at the same time) something I found very distracting is exemplified by the following line:

ExampleClass exampleObject = new ExampleClass();

It's the apparent redundant repetition that bothered me. Some light dawned when I grasped the difference between declaring a variable and assigning it a value or reference (and that these processes can be separate). However, the above usage is extremely common.

Obviously, I've learnt to live with it (and am not expecting the C# syntax to change!) but I wondered if there is a better way. Would there be any merit in the following:

exampleObject = new ExampleClass();

Where the variable exampleObject is strongly typed as ExampleClass when it is not specified?

EDIT
[after commenters pointed out ambiguity of above between a declaration of a new, and an assignment, of an existing, variable:]

An alternative hypothetical shortened syntax, which avoids the declaration/assignment ambiguity, is:

ExampleClass exampleObject = new();

...where this would create a new instance of ExampleClass, the type having been specified in the declaration of its referencing variable, exampleObject.

.. but I'm sure this opens up other problems I haven't thought of!
/EDIT

Obviously, if for some reason we wanted exampleObjectto be of type Object, or - a more common requirement - to be of the type of a parent class of ExampleClass, we would specify these types in front of the variable name in the standard way, but is there any drawback to my suggested shorthand in this very common scenario?

3
  • 5
    That's a situation where you can use var for (admittedly, quite limited) type inference: var exampleObject = new ExampleClass();. Commented Apr 18, 2014 at 10:08
  • 2
    But you can't use var on fields. Eric Lippert explains why. And obviously, you can't make a declaration without a type and without a var because then there's no way to differentiate between a declaration and an assignment.
    – Brian
    Commented Apr 18, 2014 at 10:10
  • I remain very grateful for people's helpful comments. I'm disappointed someone's now rated this question as 'not useful' or 'displaying no research effort'. This rephrasing of this point as a question was forced on me by a moderator: I knew the basic answer but I've found the extra detail more experienced programmers have provided, very illuminating. I didn't expect my raising this point to be 'useful' to most long-standing coders, but it's been very illuminating for me. Commented Apr 21, 2014 at 19:42

3 Answers 3

10

C# requires you to explicitly declare a variable, in addition to assigning it a value. This is done so that its clearer to both the compiler and the person reading the code that we're defining a new variable here, not using a previously-defined one, which can simplify parsing and make the code much clearer.

As you said, the statement ExampleClass c = new ExampleClass() is simply a contraction of both these actions, which is why you feel the duplication - it's two different actions. But it does feel clunky. This is why the C# 3.0 specifications (in VS2008) added the var keyword, which lets you skip a lot of the verbosity, even if it wasn't the primary motivation for the feature.

Using var, our example code becomes var c = new ExampleClass() - much easier to scan, but still explicitly declaring as well as assigning. It gets even more useful with long class names - var complexDictionary = new Dictionary<Tuple<int,int>, List<string>>(), for instance. Imagine writing that twice!

Of course, var was originally introduced to support anonymous types. These are used by lambda expressions and LINQ, and create types with names that are both clumsy (MyMethod<>Class5, or similar) and also not known to the developer, so that saves us a lot of problems.

Additionally, in your edit, you proposed a similar but inverse solution to the duplication - to keep the declaration explicit, but the instantiation implicit. This saves about as many characters as var, but is a lot less flexible. Consider that variable declaration is very simple - you simply state the type of your variable. Initialization, though, is more complex. Sometimes you simply use new, and then we can use your new() syntax. But often we have different constructor parameters. Or how about initializing using a factory method, like ExampleClass exampleObject = ExampleBuilder.CreateExample();? Your syntax doesn't save us anything there, whereas the type inference in var will allow us to use var exampleObject = ExampleBuilder.CreateExample(); smoothly.

3
  • 1
    @Cantabrigian I added a new example to address the suggested syntax you added in your question. Commented Apr 19, 2014 at 6:02
  • Many thanks @Avner - and to all the other people who answered. In as much as there is a 'problem', var is the 'answer'. But my post was really just to kick round something that really bothered me when I was a complete beginner. I knew some of the answers, but some of the details provided have been fascinating - e.g the link to Eric Lippert's blog post. And I shall be using 'var' much more from now on, with a clear conscience: it had always seemed to be a blow against strong typing before (even though I knew it wasn't really.) Commented Apr 20, 2014 at 11:56
  • 1
    Names like MyMethod<>Class5 are sometimes called unspeakable names. They're not just clumsy, they're not even valid type names in C# (but they are valid names in CIL).
    – svick
    Commented Apr 30, 2014 at 20:04
4

No, the repetitious syntax shouldn't bother anyone. It's kind of like complaining about the the three statements within a for loop.

for(int x = 0; x <= 100; x++) {
   /* do work */
}

Sure, you could use syntactic sugar for mocking this common pattern as below, but you don't gain a lot by any sensible alternative and, like any usage of sugar, you lose some things that are important.

for(x = 0 to 100) {
   /* do work */
}

While this is useful for the simple iteration, it's shortcomings become clear after a bit of thought:

  1. It's not possible in the shorthand for x to be anything but a locally declared variable.
  2. You can't have a more complex test, such as "skip prime numbers"
  3. You can't implicitly step by more than 1, or increment some external modifier.

Most of these can be overcome, but the syntax doesn't really help beyond some typing.


It's probably worth nothing that your one-line examples actually distort how things really should be done in C#. If we're initializing a member of a class, you really do want to do something like the following:

class Test : ITest {
    public IExample example;
    public Test() {
      example = new Example();
    }
}
  1. The type of your member is declared by way of an interface, so you can change the concrete class latter without a major code re-write.
  2. The actual initialization is in a constructor, which can be adjusted or over-ridden in a deriving class.
  3. Words like "Object" and "Class" are skipped entirely. Names are for people, and the java-like capitalization syntax does enough for our purposes.

Conversely, if you're only initalizing a local instance, you would do one of the following:

IExample example = new Example();

or

var example = new Example();
5
  • You can't have a more complex test, such as "skip prime numbers" - and does the verbose version for(int x = 0; x <= 100; x++) allow you to express that?? In both cases you would likely test i for being a prime member as the first thing to do in every iteration and continue; if it is. You can't implicitly step by more than 1 - the same could be said about foreach. Commented Apr 18, 2014 at 13:13
  • 1
    for(int x = 0; x <= 100 && NotPrime(x); x++), although a simpler test like x<=100 && x%7==0 is more likely. And forEach is a good example of why sometimes sugar is just fine.
    – DougM
    Commented Apr 18, 2014 at 15:02
  • By the way, the inexistent for (x = 0 to 100) construct could be emulated as foreach (int x in Enumerable.Range(0, 101)) in C#. Sort of Ruby style (for x in 0..100). You could even make it Enumerable.Range(0, 101).Where(NotPrime). Bad code or idiomatic C# Commented Apr 18, 2014 at 15:18
  • 6
    Actually, x <= 100 && NotPrime(x) won't skip primes, it will exit the entire loop when it hits the first prime number. Something like @Konrad's Where(NotPrime) is much easier to get right. Commented Apr 18, 2014 at 15:41
  • Saying Foo = new Foo() isn't too bad. Having to say Dictionary<String, Func<Dictionary<String, String>, IEnumerable<KeyValuePair<String,String>>> mappings = new Dictionary<String, Func<Dictionary<String, String>, IEnumerable<KeyValuePair<String,String>>>(); isn't so nice, though.
    – supercat
    Commented May 6, 2014 at 20:38
3

Yes, it bothers other people. It's a major motivation for people choosing dynamically typed languages. What you're talking about in the context of a statically typed language is called type inference, which basically means the compiler can tell what type a variable is by what type it is initialized to. It has been a full feature in languages like Scala and Haskell from the start, because of the crazy long types that come up regularly in those languages. C# supports it in a more limited form with var, and C++11 with auto.

However, note that in languages with type inference, it's still recommended to explicitly specify types on public interfaces to your code. It prevents you from accidentally changing the public interface, say if something is implemented in terms of a concrete type, but you want its public interface to be a more abstract type. It also makes it easier for consumers of your code to determine how to use it.

2
  • Just to throw in another language, F# also has type inference. (For those interested, here's an article on how F# type inference works.)
    – paul
    Commented Apr 18, 2014 at 15:59
  • That types should be clearly indicated in public interfaces doesn't imply that a class should require that they be expressed redundantly. A language could still allow MagicWidget myThing = new(23); as shorthand for MagicWidget myThing = new MagicWidget(23);, and MagicWidget myThing = .Create(23); as shorthand for MagicWidget myThing = MagicWidget.Create(23); [usages not fitting those two exact patterns would require normal syntax]
    – supercat
    Commented May 6, 2014 at 20:43

Your Answer

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

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