C# 3.0: I do not like Anonymous types
This is the my fifth post in the series of posts I am making on the new features in C#3.0. See the previous posts on var, extension method, lambda expressions and object-collection initializers
Before getting into why I do not like (actually hate) anonymous types in C#. Let's see what is this anonymous types and whats so special with this anonymity.
Anonymous types
Anonymous type is syntactic sugar to reduce typing. Let's say I need to create a structure or class to contain some data regarding customers. This is how you do it in C# 1.0
class Customer{ private string name; public string Name { get { return name; }
set { name = value; }}
private string address; public string Address { get { return address; }
set { address = value; } }} Customer cust = new Customer();cust.Name = "Abhinaba Basu";cust.Address = "Hyderabad, India";
Or using the new Object initialization syntax of C#3.0 as
var cust = new Customer{Name = "Abhinaba Basu",
Address = "Hyderabad, India"};
This is a very repitative code pattern of creating data only containers (class or struct) for the related data types. This is can be done with the Anonymous method syntax as
var cust1 = new { Name = "Abhinaba Basu",
Address = "Hyderabad, India" };
Note that in this statement I have not named a type and hence the compiler emits code to generate a new class definition whose name is not know to us and hence is a Anonymous type. The following code is generated.
public sealed class <Projection>f__0{ // Methods public <Projection>f__0(); public override bool Equals(object); public override int GetHashCode(); public override string ToString(); // Properties public string Address { get; set; } public string Name { get; set; } // Fields private string _Address; private string _Name;}
Here <Projection>f__0 is the generated class' name. For each member a private field and the corresponding property is generated. The class also generates proper implementation to override Equals, GetHashCode and ToString methods based on each of the fields. The rest of the code is same as that used for Object initialization.
If we have two such declaration that match in the field types then the same class will be used for both of them.
var cust1 = new { Name = "Abhinaba", Address = "Hyderabad" };var cust2 = new { Name = "Ankur", Address = "Noida"};if (cust1.GetType() == cust2.GetType()) Console.WriteLine("Cust1 and Cust2 are of the same type {0}", cust2.GetType().ToString());
// output:// Cust1 and Cust2 are of the same type
// AnonymousTypes.Program+<Projection>f__0
There are couple of interesting point here
- The whole thing works only for classes where you do not need to add methods
- You have to accept the compilers implementaion of the overrides.
- This works in situation where you are actually not interested to know the name of the generated class
- All the fields in the class are implicitely typed (var). So the compiler figures out the type to use (Age is Int32)
You can also use nested declaration as in
var cust = new { Name = "Abhinaba Basu",
Address = "Hyderabad, India", Phone = new { AreaCode = 33, Number = 444444} };
Why I do not like anonymous types
Again due to my upbringing in C/C++ I did not like implicit types when I saw it. This is taking the same idea to an extreme. Now not only are we letting the compiler choose the type for me I am also letting it generate new types!!!
Even without my pre-disposition I think that this construct address some special programming cases and should not have been included in the language. It'll just add to the surface area and learning curve and mainly go unused. The unusability comes from the following reasons
- Flexibility is lost. Today I have a data type that has only data and right now I do not care about the exact type. If in the future I need to add some method to it (say to change the Equals override) I need to change all the places where I used the anonymous types and convert them to named types.
- I decide to add a new field to the class which is used by some of the object and not by some. At the same time I need all of the objects to be of the same type (maybe because I compare them) then I need to go and make changes at all the object allocation code
var cust = new { Name = "Abhinaba Basu", Address = "Hyderabad, India", phone } - Readability of the code is lost. If I have an API like void Show(var value) and I call it as follows
var cust = new { Name = "foo", Address="bar");
Show(cust);
then this does not convey much. The alternative is much more readable when void Show (Customer cust) is defined and used as follows
Customer cust = new Customer { Name = "foo", Address="bar");
Show (cust);
Comments
Anonymous
September 18, 2005
The comment has been removedAnonymous
September 18, 2005
There is something deliciously ironic about a C/C++ programmer complaining about new language features causing code to become unreadable. Is it the voice of experience perhaps? ;)Anonymous
September 18, 2005
The comment has been removedAnonymous
September 18, 2005
The comment has been removedAnonymous
September 19, 2005
I absolutely agree that in some situation these features come in handy as in creating data types out of Linq queries. If you talk to a function programmer he'll tell you in length that life without continuation support is not possible. The point is all of them have their context and usage. If you try to pull in all of them into the same language and point to individual usage as the justification soon you'll have a language which'll be too huge and complex to use. Every language has a nature and people using it are used to it. We all know that object oriented design works well in some situation so does that mean that functional languages will start using them? They won't, and similarly C# should not start adopting functional programming paradigm, cause its so different for people moving into C# from C/C++ background that they'll get alienated when they get to maintain code with Lambda expressions and anonymous types/methods. As Joe Chung has pointed out this is the voice of experience. Wait till Boost lib starts getting standardized into ANSI C++ and as a C++ dev you suddently get code like for_each(a.begin(), a.end(), std::cout << _1 << ' '); to maintain.Anonymous
September 19, 2005
The comment has been removedAnonymous
September 19, 2005
"Wait till Boost lib starts getting standardized into ANSI C++"
I've been holding my breath for 3 years now =(Anonymous
September 19, 2005
The comment has been removedAnonymous
September 19, 2005
I did not see in the spec that anonymous types cannot exit the scope of the current method. If this is true then a lot of my concerns are gone as the type will be used locally in a function and hence chances of passing them around and creating ambiguity is gone.
Anonymous types does work beautifully in case of grouping data in Linq queries. Which I plan to cover in my next post.Anonymous
September 20, 2005
The comment has been removedAnonymous
September 22, 2005
I think it's safe to say that you can return anonymous types from a function -- that's how functions like .Select() work!
In order to do "select x.Name, x.Age", the compiler creates a function that takes an x and returns a new {string Name, int Age}; it then passes that function to .Select(), which returns an IEnumerable<{string Name,int Age}>.
So while you may not be able to specify 'var' as the return type of a method, you can absolutely return these types from functions!Anonymous
September 28, 2005
The comment has been removedAnonymous
October 03, 2005
I think your hate of anonymous types is erroneous. I have some across many people mistaking 'var' as an equivalent to the Variant type of VBScript or JavaScript. It is, like you described anonymous types, syntactic sugar, nothing more. You mention that readability is lost, such as the API 'Show(var value)' implying that somehow 'value' has no strong type and is a variant. This concept does not exist in the C# 3.0 spec. According to the C# 3.0 language specification, this piece of code would not compile since there is no initializer, and thus nothing to infer the type from.
For more info, see section 26.1 of the C# 3.0 Language Spec: http://download.microsoft.com/download/9/5/0/9503e33e-fde6-4aed-b5d0-ffe749822f1b/csharp%203.0%20specification.docAnonymous
April 20, 2006
it's funny how many people don't seem to understand "var" at all and have jumped to the conclusion that it's similar or the same as VB6's "Variant" data type.
i hate how every time a nice new language feature comes out there's a giant crowd of people complaining because they don't want to learn something new or they're afraid that they'll shoot their eye out with it.Anonymous
August 09, 2006
The comment has been removedAnonymous
January 14, 2007
The problem with anonymous types isn't that they can 'break' things. As mentioned earlier you cannot use them outside of the scope of methods. The problem is there isn't mush you CAN do with them. So I used them as data containers for a query result then what, I have to iterate through my result using reflection of all things to get my data back!?! just what in heavens name are you supposed to do with a complex nested result set when you don't knwo what the type name is and there's no way to explicitly access all the properties you've created?Anonymous
June 15, 2007
It's been years since I last saw you.,It's been years since I last saw you.,It's been years since I last saw you.,It's been years since I last saw you.Anonymous
June 15, 2007
It's been years since I last saw you.,It's been years since I last saw you.,It's been years since I last saw you.,It's been years since I last saw you.Anonymous
July 29, 2007
please there a certain web which cannot browse through till the end without having complain from the company so please i will like you to give me or to discribe me a good proxy to use that will help me open these web please these web are many and especialy in cameroon they are website like kansas.com,kansascity.com thanksAnonymous
December 03, 2007
- Obviously, Microsoft needed anonymous types for LINQ. Someone would complain if they didn't expose that for the rest of us.
- I can write unreadable code with or without anonymous types and I can write readable code WITH anonymous types. The problem isn't anonymous types, the problem is the person using it.
- Just because a feature is available doesn't mean it should be used all of the time. Ternary operators are also useful occasionally, but programmer in their right mind would consider using them in place of a standard if/then/else construct. (Of course, you could find programmers who are out of their minds who do use them in place of if/then/else.)
Anonymous
December 03, 2007
The comment has been removedAnonymous
January 23, 2008
I was initially suspicious but having read through this thoughtful discussion on both sides, I am comforted :) And in fact, many times the structure of data mirrors the structure of code. Having a flexible bag to hold arbitrary typed collections, and so avoid the ugliness of casting and obfuscation indexed references, is nice. After all, the holy grail is clarity. for example (contrieved)... var x if (a) x = new {y,c,b,...} else x = new {y,c,a,...} ... .. for (int i = 0; i < x.y;...) if (x.c) x.b... else if (x.b) .... else if (x.a) ...Anonymous
March 06, 2008
PingBack from http://michaelsync.net/2008/03/06/c-30-tutorials-understanding-about-anonymous-typesAnonymous
April 01, 2008
George, that won't compile. vars must be initialized at declaration time. Anyway since vars and anonymous types are still statically typed and are confined to the scope of a single method, I don't see what the fuss is about. Obviously their primary purpose is for LINQ. (The only way to get them out of a method is with generics, which is how LINQ does it. And this is perfectly reasonable, as that's the point of generics - to be generic).Anonymous
June 05, 2008
anonymous types are a benefit when you are creating view objects from a linq query. You don't know how to use it properlyAnonymous
November 03, 2009
The comment has been removed