is it bad to use initializer block - c#

Hi I use initializer block in C#
new Something { foo = 1, bar = 2 };
but people say this is bad practice.
I don't think it is wrong, is it?

You need to ask yourself whether your type should be mutable or not. Personally, I like immutable types - they make it easier to reason about what's going on, easier to validate (once the constructor has been called and the state validated, you know it's not going to become invalid) and they're great for concurrency.
On the other hand, object initializers are certainly useful in cases where it is reasonable to have mutable types. As an example, ProcessStartInfo is effectively used as a builder type for Process. It's useful to be able to write:
var info = new ProcessStartInfo {
FileName = "notepad.exe",
Arguments = "foo.txt",
ErrorDialog = true
};
Process process = Process.Start(info);
Indeed, you can even do all this inline instead of having an extra variable. My Protocol Buffers port uses the same sort of pattern:
Foo foo = new Foo.Builder {
FirstProperty = "first",
SecondProperty = "second"
}.Build();
Now one alternative to the builder pattern is constructor parameters (possibly via factory methods). The historical downside of this is that you needed different overloads depending on which properties were being set, and if several parameters had the same type it could be hard to tell which was which. C# 4 makes this significantly easier using optional parameters and named arguments. For example, if you're building an email class you could have:
Email email = new Email(
from: "skeet#pobox.com",
to: "jon#example.com",
subject: "Test email",
body: textVariable
);
This has many of the same benefits of object initializers in terms of clarity, but without the mutability penalty. The constructor call above may have missed out some optional parameters such as attachments and a BCC list. I think this will prove to be one of the biggest benefits of C# 4 for those of us who like immutability but also like the clarity of object initializers.

It's questionable (I won't say "bad") practice to use initialization blocks as a substitute for the appropriate constructor overload, if one exists.
public class Entity
{
public Entity()
{
}
public Entity(int id, string name)
{
this.ID = id;
this.Name = name;
}
public int ID { get; set; }
public string Name { get; set; }
}
If you have this very simple class, then it is generally preferable to write:
var entity = new Entity(1, "Fred");
...than it is to write:
var entity = new Entity { ID = 1, Name = "Fred" };
There are at least two good reasons for this:
You don't know exactly what the constructor is doing. It's possible that, in some circumstances, it might be significantly more expensive to construct the object and then set public properties vs. passing the values through the constructor itself. (You may know that this is not the case, but as the consumer of a class, you shouldn't presume to know care about the implementation details, because they are subject to change).
Your code won't break if one or more of those properties have their names changed, or become read-only (which the ID probably should have been in the first place, but perhaps wasn't due to architectural constraints like that of an ORM).
However, there is one case where you have to use initializers instead of overloaded constructors, and that is when chaining selects in a Linq to SQL/EF query:
var bars =
from f in ctx.Foo
select new Bar { X = f.X, Y = f.Y };
var bazzes =
from b in bars
select new Baz { ... };
This can actually fail with a "no supported mapping" if you use constructor overloads instead of default constructors + initializers. This is, however, a constraint of the technology being used (and an undesirable one at that), and not a coding style issue.
In other cases, you should prefer the constructor overload over the initializer.
If there is no useful/relevant constructor overload that can do the same thing as your initializer, then go ahead and write the initializer, there's nothing wrong with it. The feature exists for a good reason - it makes the code easier to write and read.

but people say is bad practice.
Who says this? At the very least, that’s a controversial statement.
It seems to be all the rage at the moment, and many prominent C# blogs use it extensively.
The advantage over using a constructor is that it’s more readable since the code clearly shows which properties get assigned what values. Compare:
var x = new Something { Foo = 1, Bar = 2 };
with
var x = new Something(1, 2);
Furthermore, if no appropriate constructor is present, the code is more concise than manually assigning to properties:
var x = new Something();
x.Foo = 1;
x.Bar = 2;
Personally, I prefer immutable objects (i.e. objects that, once created, cannot be changed). Unfortunately, the initializer blocks cannot be used in conjunction with such objects (at the moment) because to make this pattern work the object has to have property setters, which an immutable object doesn’t have.
But as long as the object used isn’t immutable I don’t see a compelling reason against using the initializer notation.

Initializer blocks are GREAT practice for the following reasons:
You get to create an object and override its properties before getting its reference
this.ObjA = new ObjA
{
Age = 20,
Name = "123",
};
// this.ObjA will not be set until properties have all been defined
// - safer when multithreading
The parameter-less constructor can still do things behind the scene
(e.g. initialize state members).
You can use in conjunction with constructors with parameters
this.ObjA = new ObjA(20)
{
Name = "123",
};
Using parameter-less constructors is better for (de)serializing scenarios
You can create various objects, change their state via GUI, serialize them, deserialize them elsewhere.
This practice forces authors to write more robust code - where the order in which things are done is less lightly to cause the application to crash every time the class's metadata is changed.

There is nothing wrong with initializer blocks, but if your type for example has many properties, and only a couple of them need to be set on every instance, then you should make them required in a constructor.
The user of your class will know that they can't create an object without specifying those values.

The properties that are essential for the object work, should be initialized in the constructor, so you should provide the appropiate parameters in hthe contstructor.
Initializer blocks are very handy for several of the new features of C# 3.0, but you should keep in mind, that they are not here for replace the parameters in the constructor.

I think it's good.
Because it reduces your typing a lot

Related

Validation of a C# object initialized with init-only setters

Disclaimer for re-opening
This question is about object validation of an immutable object during construction using C# 9 init-only setters (as opposed to using a constructor with verbose "boiler plate code").
C# 9 introduces an option to initialize immutable object with object initializer syntax, using init only setters:
class Immutable
{
public string Name { get; init; }
public int Value { get; init; }
}
Immutable o = new Immutable { Name = "Value1", Value = 257 };
Additionally it introduces a nice syntax to create mutated copies of an object:
var o1 = o with { Value = 65537 };
Previously the only option to create and initialize a new immutable object was to use constructor with parameters. The new option is more natural and elegant, but one important feature of constructor initialization is missing: validation. With constructor I can be sure to never create an object with invalid state.
It is possible to put validation code into init setters, but there's no way, of which I'm aware of, to provide a general validation of object state as a whole. Specifically, I don't see any way to assure in the example above that Name property will fulfill its contract to have a non-null value. As parameterless constructor is necessary to use object initializer syntax, it is possible to create an uninitialized instance:
var o = new Immutable();
in which case properties will get default values.
Question [edit]: is there any method to validate immutable object state after initialization with init setters is complete? Keep in mind that property assignments may be not specified in the initialization statement and the default object state may be invalid.
I've finally found the information on validation in Mads Torgersen's comment under his post on C# 9. They are looking into options to introduce this in C# 10.
[Edit] If was finally, at least partially, resolved in C# 11 by introduction of required keyword, which can be used on properties. This is quite elegant solution, because it forces assignment on source code level (IDE hilights missing assignments). Still, ability to run some code after all assignments have been made would be useful.

When using object initializers, what does the parenthesis do? [duplicate]

It seems that the C# 3.0 object initializer syntax allows one to exclude the open/close pair of parentheses in the constructor when there is a parameterless constructor existing. Example:
var x = new XTypeName { PropA = value, PropB = value };
As opposed to:
var x = new XTypeName() { PropA = value, PropB = value };
I'm curious why the constructor open/close parentheses pair is optional here after XTypeName?
This question was the subject of my blog on September 20th 2010. Josh and Chad's answers ("they add no value so why require them?" and "to eliminate redundancy") are basically correct. To flesh that out a bit more:
The feature of allowing you to elide the argument list as part of the "larger feature" of object initializers met our bar for "sugary" features. Some points we considered:
the design and specification cost was low
we were going to be extensively changing the parser code that handles object creation anyway; the additional development cost of making the parameter list optional was not large compared to the cost of the larger feature
the testing burden was relatively small compared to the cost of the larger feature
the documentation burden was relatively small compared...
the maintenance burden was anticipated to be small; I don't recall any bugs reported in this feature in the years since it shipped.
the feature does not pose any immediately obvious risks to future features in this area. (The last thing we want to do is make a cheap, easy feature now that makes it much harder to implement a more compelling feature in the future.)
the feature adds no new ambiguities to the lexical, grammatical or semantic analysis of the language. It poses no problems for the sort of "partial program" analysis that is performed by the IDE's "IntelliSense" engine while you are typing. And so on.
the feature hits a common "sweet spot" for the larger object initialization feature; typically if you are using an object initializer it is precisely because the constructor of the object does not allow you to set the properties you want. It is very common for such objects to simply be "property bags" that have no parameters in the ctor in the first place.
Why then did you not also make empty parentheses optional in the default constructor call of an object creation expression that does not have an object initializer?
Take another look at that list of criteria above. One of them is that the change does not introduce any new ambiguity in the lexical, grammatical or semantic analysis of a program. Your proposed change does introduce a semantic analysis ambiguity:
class P
{
class B
{
public class M { }
}
class C : B
{
new public void M(){}
}
static void Main()
{
new C().M(); // 1
new C.M(); // 2
}
}
Line 1 creates a new C, calls the default constructor, and then calls the instance method M on the new object. Line 2 creates a new instance of B.M and calls its default constructor. If the parentheses on line 1 were optional then line 2 would be ambiguous. We would then have to come up with a rule resolving the ambiguity; we could not make it an error because that would then be a breaking change that changes an existing legal C# program into a broken program.
Therefore the rule would have to be very complicated: essentially that the parentheses are only optional in cases where they don't introduce ambiguities. We'd have to analyze all the possible cases that introduce ambiguities and then write code in the compiler to detect them.
In that light, go back and look at all the costs I mention. How many of them now become large? Complicated rules have large design, spec, development, testing and documentation costs. Complicated rules are much more likely to cause problems with unexpected interactions with features in the future.
All for what? A tiny customer benefit that adds no new representational power to the language, but does add crazy corner cases just waiting to yell "gotcha" at some poor unsuspecting soul who runs into it. Features like that get cut immediately and put on the "never do this" list.
How did you determine that particular ambiguity?
That one was immediately clear; I am pretty familiar with the rules in C# for determining when a dotted name is expected.
When considering a new feature how do you determine whether it causes any ambiguity? By hand, by formal proof, by machine analysis, what?
All three. Mostly we just look at the spec and noodle on it, as I did above. For example, suppose we wanted to add a new prefix operator to C# called "frob":
x = frob 123 + 456;
(UPDATE: frob is of course await; the analysis here is essentially the analysis that the design team went through when adding await.)
"frob" here is like "new" or "++" - it comes before an expression of some sort. We'd work out the desired precedence and associativity and so on, and then start asking questions like "what if the program already has a type, field, property, event, method, constant, or local called frob?" That would immediately lead to cases like:
frob x = 10;
does that mean "do the frob operation on the result of x = 10, or create a variable of type frob called x and assign 10 to it?" (Or, if frobbing produces a variable, it could be an assignment of 10 to frob x. After all, *x = 10; parses and is legal if x is int*.)
G(frob + x)
Does that mean "frob the result of the unary plus operator on x" or "add expression frob to x"?
And so on. To resolve these ambiguities we might introduce heuristics. When you say "var x = 10;" that's ambiguous; it could mean "infer the type of x" or it could mean "x is of type var". So we have a heuristic: we first attempt to look up a type named var, and only if one does not exist do we infer the type of x.
Or, we might change the syntax so that it is not ambiguous. When they designed C# 2.0 they had this problem:
yield(x);
Does that mean "yield x in an iterator" or "call the yield method with argument x?" By changing it to
yield return(x);
it is now unambiguous.
In the case of optional parens in an object initializer it is straightforward to reason about whether there are ambiguities introduced or not because the number of situations in which it is permissible to introduce something that starts with { is very small. Basically just various statement contexts, statement lambdas, array initializers and that's about it. It's easy to reason through all the cases and show that there's no ambiguity. Making sure the IDE stays efficient is somewhat harder but can be done without too much trouble.
This sort of fiddling around with the spec usually is sufficient. If it is a particularly tricky feature then we pull out heavier tools. For example, when designing LINQ, one of the compiler guys and one of the IDE guys who both have a background in parser theory built themselves a parser generator that could analyze grammars looking for ambiguities, and then fed proposed C# grammars for query comprehensions into it; doing so found many cases where queries were ambiguous.
Or, when we did advanced type inference on lambdas in C# 3.0 we wrote up our proposals and then sent them over the pond to Microsoft Research in Cambridge where the languages team there was good enough to work up a formal proof that the type inference proposal was theoretically sound.
Are there ambiguities in C# today?
Sure.
G(F<A, B>(0))
In C# 1 it is clear what that means. It's the same as:
G( (F<A), (B>0) )
That is, it calls G with two arguments that are bools. In C# 2, that could mean what it meant in C# 1, but it could also mean "pass 0 to the generic method F that takes type parameters A and B, and then pass the result of F to G". We added a complicated heuristic to the parser which determines which of the two cases you probably meant.
Similarly, casts are ambiguous even in C# 1.0:
G((T)-x)
Is that "cast -x to T" or "subtract x from T"? Again, we have a heuristic that makes a good guess.
Because that's how the language was specified. They add no value, so why include them?
It's also very similar to implicity typed arrays
var a = new[] { 1, 10, 100, 1000 }; // int[]
var b = new[] { 1, 1.5, 2, 2.5 }; // double[]
var c = new[] { "hello", null, "world" }; // string[]
var d = new[] { 1, "one", 2, "two" }; // Error
Reference: http://msdn.microsoft.com/en-us/library/ms364047%28VS.80%29.aspx
This was done to simplify the construction of objects. The language designers have not (to my knowledge) specifically said why they felt that this was useful, though it is explicitly mentioned in the C# Version 3.0 Specification page:
An object creation expression can omit the constructor argument list and enclosing parentheses, provided it includes an object or collection initializer. Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.
I suppose that they felt the parenthesis, in this instance, were not necessary in order to show developer intent, since the object initializer shows the intent to construct and set the properties of the object instead.
In your first example, the compiler infers that you're calling the default constructor (the C# 3.0 Language Specification states that if no parenthesis are provided, the default constructor is called).
In the second, you explicitly call the default constructor.
You can also use that syntax to set properties while explicitly passing values to the constructor. If you had the following class definition:
public class SomeTest
{
public string Value { get; private set; }
public string AnotherValue { get; set; }
public string YetAnotherValue { get; set;}
public SomeTest() { }
public SomeTest(string value)
{
Value = value;
}
}
All three statements are valid:
var obj = new SomeTest { AnotherValue = "Hello", YetAnotherValue = "World" };
var obj = new SomeTest() { AnotherValue = "Hello", YetAnotherValue = "World"};
var obj = new SomeTest("Hello") { AnotherValue = "World", YetAnotherValue = "!"};
I am no Eric Lippert, so I can't say for sure, but I would assume it is because the empty parenthesis is not needed by the compiler in order to infer the initialization construct. Therefore it becomes redundant information, and not needed.

Why use anonymous type(and thus var)

I'm new to c# and I'm totally against var.
Every time when I see var in code example, it makes me crazy, "what type is it?" even the semantic is obvious, I'd like to see the full type name. The presence of full type name makes me feel that the code is elegant and professional.
I know var can be necessary if using an anonymous type, but I'm against anonymous type too. If you want to use a type, why not give it a name? The following is some example of using var:
var results = context.People.Select(p => new {p.PersonID, p.Name});
But I think it should be written like this: (Don't argue about the definition or syntax, I'm not sure whether it's correct because I'm not familiar with linq, I just want to say "why not give it a name?")
class Result
{
public int PersonID;
public string Name;
public Result(int id, string name)
{
PersonID = id;
Name = name;
}
}
Result results = context.People.Select(p => new Result(p.PersonID, p.Name));
First, let's fix your code:
class Result
{
public int PersonID;
public string Name;
public Result(int id, string name)
{
PersonID = id;
Name = name;
}
}
IEnumerable<Result> results = context.People.Select(p => new Result(p.PersonID, p.Name));
And to be honest, it should be pretty apparent by now why many like 'var' and anonymous types - your version is significantly more verbose.
In particular in LINQ queries you often want a data type for a very limited scope - so the cost of defining a new data type is excessive and provides little value. Another situation I see a lot is where the anonymous type is used to be serialised (e.g. to json) - where having the data and field names written together makes for nice simple code.
new {Name = "Mike", Version = 1, Date = DateTime.Now}.ToJson();
Anonymous types (and Tuples for that matter) make it easier to maintain your code without a hundred tiny classes created for the sole purpose of passing a couple values around between methods or even within a single method.
You can read some arguments for the use of both in an article by James Hare called "The Joy of Tuples and Anonymous Types".
As for var, I suppose that in most cases it's a matter of readability. In certain cases, it's easy to see which type var will be declared as.
SomeClassThatINeedToUse myInstance = new SomeClassThatINeedToUse();
var myInstance = new SomeClassThatINeedToUse();
When you work on a big application, you come across too many scenarios (writing LINQ queries) where you don't want to define a class for every small structure that you are about to arrive at.
Keep things simple!!
IMO, usage of keyword var is just a personal choice; but anonymous types - just too good to resist using.
Here's an old thread with much more discussion than you're likely to get, here: Use of var keyword in C#

Object Initializer force compile error

Is it possible to enforce rules or throw an error when using object initializers in C#? I'd like to throw a compiler error or warning if an object is initialized but is missing a certain property.
public class Party
{
public string Name { get; set; }
public string Date { get; set; }
public Location Location { get; set; }
}
public class SignUpForParty
{
public void DoSomething()
{
Party party = new Party()
{
Name = "New Years Party!",
Date = "Dec 31, 1999"
// Show WARNING/ERROR here because no Location given
};
}
}
Essentially, I'm looking for a way to ensure that all objects of type Party are created with valid data for every instance.
Obviously I could do this with overloaded constructors, but in some cases I have a lot of properties and writing constructors to match is messy. I'd like to follow a cleaner C# style.
Obj p = new Obj(1, 2, 3,...n); // too many properties to be pretty
Obviously I could do this with overloaded constructors, but in some cases I have a lot of properties and writing constructors to match is messy. I'd like to follow a cleaner C# style.
Object initializers really shouldn't be considered alternatives to writing a constructor.
You should always include constructors in your types if you have requirements like this. It is a good idea to create a default set of constructors (or use optional arguments on one constructor) which at least provide a guarantee that the object will always be created in a valid, meaningful state.
Object initializers are helpful for optional properties, but shouldn't be relied upon for requirements of your type itself.
You cannot force every property to be initialized with an object initializer.
Even if you could, a consumer of the object could provide default (0, null, ...) values. Depending on your needs, consider validating object state at key times (e.g. before it can be saved to a database).
If you go that route, have a look at the IDataErrorInfo interface.
If your type is not valid when only 2 properties are set then you need to fix your design, not emit an error.
You provide a default constructor, which tells me that I don't have to set anything to use the object after initialization. You provide getters and setters for each property, again, implicitly telling users of your class that it is ok to set on but not the other.
If this is not the case then I suggest you provide a constructor which forces me to supply all three values. Yes, I can still use (null, null, null), but you could check for that and throw an error.
Also, if PropertyA is dependent on PropertyB then either
A) Only one of them should have a setter, or
B) There should be logic in the setter of each to properly initialize the other after the value changes.
This is a design problem, not a language problem. You cannot force the initializer syntax to work differently than how it was spec'd.
Obj p = new Obj(1, 2, 3,...n); // too many properties to be pretty
Code isn't supposed to be 'pretty', it is supposed to work. Even then, a constructor which takes a few arguments is 'ugly'? Huh? Don't buy into the hipster nonsense, write code that works and works well.
The only way I could see this implemented is if there was some event (or equivalent) that was raised when the object initializer was completed. There is currently a Connect request for something to this effect.
Unfortunately, I didn't make the cut for .NET 4.5:
Thank you for your suggestion.
This is a great idea, and has the nice property that it doesn't add to the language surface - it just makes object initializers smarter. In principle that would probably make it a breaking change, but that is something we can look into.
Unfortunately we cannot add any more to the release we are currently building, so I am going to resolve as Won't fix for this release. However, I am capturing the suggestion on our list of features for future discussion.
Thanks again!
Mads Torgersen, C# Language PM
Maybe it'll make it's way into .NET 5+.
What about Code Contracts?. This will assert not only that you assigned a value, but you could also specify valid ranges.
Or for check at runtime with debug builds only, you could use Debug.Assert(...) calls to achieve the same as above.

Why are C# 3.0 object initializer constructor parentheses optional?

It seems that the C# 3.0 object initializer syntax allows one to exclude the open/close pair of parentheses in the constructor when there is a parameterless constructor existing. Example:
var x = new XTypeName { PropA = value, PropB = value };
As opposed to:
var x = new XTypeName() { PropA = value, PropB = value };
I'm curious why the constructor open/close parentheses pair is optional here after XTypeName?
This question was the subject of my blog on September 20th 2010. Josh and Chad's answers ("they add no value so why require them?" and "to eliminate redundancy") are basically correct. To flesh that out a bit more:
The feature of allowing you to elide the argument list as part of the "larger feature" of object initializers met our bar for "sugary" features. Some points we considered:
the design and specification cost was low
we were going to be extensively changing the parser code that handles object creation anyway; the additional development cost of making the parameter list optional was not large compared to the cost of the larger feature
the testing burden was relatively small compared to the cost of the larger feature
the documentation burden was relatively small compared...
the maintenance burden was anticipated to be small; I don't recall any bugs reported in this feature in the years since it shipped.
the feature does not pose any immediately obvious risks to future features in this area. (The last thing we want to do is make a cheap, easy feature now that makes it much harder to implement a more compelling feature in the future.)
the feature adds no new ambiguities to the lexical, grammatical or semantic analysis of the language. It poses no problems for the sort of "partial program" analysis that is performed by the IDE's "IntelliSense" engine while you are typing. And so on.
the feature hits a common "sweet spot" for the larger object initialization feature; typically if you are using an object initializer it is precisely because the constructor of the object does not allow you to set the properties you want. It is very common for such objects to simply be "property bags" that have no parameters in the ctor in the first place.
Why then did you not also make empty parentheses optional in the default constructor call of an object creation expression that does not have an object initializer?
Take another look at that list of criteria above. One of them is that the change does not introduce any new ambiguity in the lexical, grammatical or semantic analysis of a program. Your proposed change does introduce a semantic analysis ambiguity:
class P
{
class B
{
public class M { }
}
class C : B
{
new public void M(){}
}
static void Main()
{
new C().M(); // 1
new C.M(); // 2
}
}
Line 1 creates a new C, calls the default constructor, and then calls the instance method M on the new object. Line 2 creates a new instance of B.M and calls its default constructor. If the parentheses on line 1 were optional then line 2 would be ambiguous. We would then have to come up with a rule resolving the ambiguity; we could not make it an error because that would then be a breaking change that changes an existing legal C# program into a broken program.
Therefore the rule would have to be very complicated: essentially that the parentheses are only optional in cases where they don't introduce ambiguities. We'd have to analyze all the possible cases that introduce ambiguities and then write code in the compiler to detect them.
In that light, go back and look at all the costs I mention. How many of them now become large? Complicated rules have large design, spec, development, testing and documentation costs. Complicated rules are much more likely to cause problems with unexpected interactions with features in the future.
All for what? A tiny customer benefit that adds no new representational power to the language, but does add crazy corner cases just waiting to yell "gotcha" at some poor unsuspecting soul who runs into it. Features like that get cut immediately and put on the "never do this" list.
How did you determine that particular ambiguity?
That one was immediately clear; I am pretty familiar with the rules in C# for determining when a dotted name is expected.
When considering a new feature how do you determine whether it causes any ambiguity? By hand, by formal proof, by machine analysis, what?
All three. Mostly we just look at the spec and noodle on it, as I did above. For example, suppose we wanted to add a new prefix operator to C# called "frob":
x = frob 123 + 456;
(UPDATE: frob is of course await; the analysis here is essentially the analysis that the design team went through when adding await.)
"frob" here is like "new" or "++" - it comes before an expression of some sort. We'd work out the desired precedence and associativity and so on, and then start asking questions like "what if the program already has a type, field, property, event, method, constant, or local called frob?" That would immediately lead to cases like:
frob x = 10;
does that mean "do the frob operation on the result of x = 10, or create a variable of type frob called x and assign 10 to it?" (Or, if frobbing produces a variable, it could be an assignment of 10 to frob x. After all, *x = 10; parses and is legal if x is int*.)
G(frob + x)
Does that mean "frob the result of the unary plus operator on x" or "add expression frob to x"?
And so on. To resolve these ambiguities we might introduce heuristics. When you say "var x = 10;" that's ambiguous; it could mean "infer the type of x" or it could mean "x is of type var". So we have a heuristic: we first attempt to look up a type named var, and only if one does not exist do we infer the type of x.
Or, we might change the syntax so that it is not ambiguous. When they designed C# 2.0 they had this problem:
yield(x);
Does that mean "yield x in an iterator" or "call the yield method with argument x?" By changing it to
yield return(x);
it is now unambiguous.
In the case of optional parens in an object initializer it is straightforward to reason about whether there are ambiguities introduced or not because the number of situations in which it is permissible to introduce something that starts with { is very small. Basically just various statement contexts, statement lambdas, array initializers and that's about it. It's easy to reason through all the cases and show that there's no ambiguity. Making sure the IDE stays efficient is somewhat harder but can be done without too much trouble.
This sort of fiddling around with the spec usually is sufficient. If it is a particularly tricky feature then we pull out heavier tools. For example, when designing LINQ, one of the compiler guys and one of the IDE guys who both have a background in parser theory built themselves a parser generator that could analyze grammars looking for ambiguities, and then fed proposed C# grammars for query comprehensions into it; doing so found many cases where queries were ambiguous.
Or, when we did advanced type inference on lambdas in C# 3.0 we wrote up our proposals and then sent them over the pond to Microsoft Research in Cambridge where the languages team there was good enough to work up a formal proof that the type inference proposal was theoretically sound.
Are there ambiguities in C# today?
Sure.
G(F<A, B>(0))
In C# 1 it is clear what that means. It's the same as:
G( (F<A), (B>0) )
That is, it calls G with two arguments that are bools. In C# 2, that could mean what it meant in C# 1, but it could also mean "pass 0 to the generic method F that takes type parameters A and B, and then pass the result of F to G". We added a complicated heuristic to the parser which determines which of the two cases you probably meant.
Similarly, casts are ambiguous even in C# 1.0:
G((T)-x)
Is that "cast -x to T" or "subtract x from T"? Again, we have a heuristic that makes a good guess.
Because that's how the language was specified. They add no value, so why include them?
It's also very similar to implicity typed arrays
var a = new[] { 1, 10, 100, 1000 }; // int[]
var b = new[] { 1, 1.5, 2, 2.5 }; // double[]
var c = new[] { "hello", null, "world" }; // string[]
var d = new[] { 1, "one", 2, "two" }; // Error
Reference: http://msdn.microsoft.com/en-us/library/ms364047%28VS.80%29.aspx
This was done to simplify the construction of objects. The language designers have not (to my knowledge) specifically said why they felt that this was useful, though it is explicitly mentioned in the C# Version 3.0 Specification page:
An object creation expression can omit the constructor argument list and enclosing parentheses, provided it includes an object or collection initializer. Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.
I suppose that they felt the parenthesis, in this instance, were not necessary in order to show developer intent, since the object initializer shows the intent to construct and set the properties of the object instead.
In your first example, the compiler infers that you're calling the default constructor (the C# 3.0 Language Specification states that if no parenthesis are provided, the default constructor is called).
In the second, you explicitly call the default constructor.
You can also use that syntax to set properties while explicitly passing values to the constructor. If you had the following class definition:
public class SomeTest
{
public string Value { get; private set; }
public string AnotherValue { get; set; }
public string YetAnotherValue { get; set;}
public SomeTest() { }
public SomeTest(string value)
{
Value = value;
}
}
All three statements are valid:
var obj = new SomeTest { AnotherValue = "Hello", YetAnotherValue = "World" };
var obj = new SomeTest() { AnotherValue = "Hello", YetAnotherValue = "World"};
var obj = new SomeTest("Hello") { AnotherValue = "World", YetAnotherValue = "!"};
I am no Eric Lippert, so I can't say for sure, but I would assume it is because the empty parenthesis is not needed by the compiler in order to infer the initialization construct. Therefore it becomes redundant information, and not needed.

Categories

Resources