CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeffrey Palermo (.com)

Blog moved to www.jeffreypalermo.com

Use caution with anonymous types and other new C# language features

To subscribe to my feed, add the following Url:  http://feeds.feedburner.com/jeffreypalermo.

I think Microsoft is making a huge mistake by leaning so heavily on anonymous types as API parameters, particularly in the ASP.NET MVC Framework.  Not only does this make the APIs in the system ugly and error-prone, but it's not intuitive, and there is no intellisense for it because the API is untyped (typed as object) in the case where an anonymous type is expected.  I think we should stick with named types and named methods wherever possible.  I currently don't see a problem with lamda's if they give an advantage over regular arguments. I'm very cautious about automatically using new, unproven language features before we fully understand how they will affect the usability and maintainability of code.  Note:  we have NO track record for the maintainability of these new language features, and they were developed specifically for LINQ, so using them outside of that context is suspect, in my opinion.

I do have a conservative disposition on this, but this is through learning from the past.  I still remeber OpenXML is SQL Server 2000: how so many developers automatically converted stored procedure interfaces to be a single XML string rather than individual arguments.  We need to fully understand the long-term strengths and weaknesses of features in order to maximize the value of usage or non-usage.



Comments

Aaron Erickson said:

I guess I should start paying more attention - I thought anonymous types were for local scope, transient shapes of data.  That is the only real place where I find something like that useful.

Having a public interface use an anonymous type seems like a really, really bad idea.

# February 8, 2008 1:08 PM

Ran Davidovitz said:

I see the option to pass anonymous types same as passing an System.Object (or actually an open dictionary).

While using Anonymous types make the code more generic and add ease of programming it still causes, as you said, to not see the full contact of the API and eventually people will always need to read the manual to use the API.

You can see example for this in ExtJS framework (JavaScript) that the constructor get a JSON object that you simply have no way to know what to pass without re-reading the docs.

# February 8, 2008 1:18 PM

wekempf said:

I don't think you are informed on this topic.  In C#, anonymous types can't be used in the public interface.  The work only in local scope.  They are also strongly typed.  The IDE understands them just fine, and displays the appropriate intellisense.

You'll have to be a lot more specific about how you think this concept is harmful, especially with regard to the MVC framework.  Where is an anonymous type used as an API parameter there?

# February 8, 2008 3:09 PM

Garry Shutler said:

@wekemf, if you want to create default parameters or create a link to a specific controller action you have to use something like new { controller = "MyController", action = "MyAction" }

# February 8, 2008 3:26 PM

Jeffrey Palermo said:

@wekempf,

No problem.  I can be more specific.  Let's take the Route class, which is one of the first things you define when creating an ASP.NET MVC application:

public class Route

{

. . . .

   // Methods

   public Route();

   public Route(string url, Type routeHandler);

   public Route(string url, object defaults, Type routeHandler);

. . . .

   public object Defaults { get; set; }

. . .

}

In the constructor, what is this object "default".  The property "Defaults".  What is the type?  This is specifically what I'm talking about.  What is _expected_ is that an anonymous type with _just_ the right property spellings is passed in.  This is a bad API.  Clearly the class requires a specific object with specific properties, but the API lies and communicates that any object will do.

# February 8, 2008 3:30 PM

Alan Mojab said:

I tend to agree with you on anonymous type issues. I’ve recently read about “Dynamic Lookup” another late binding language feature MS is adding to CLI 4.0.

I think in real world both Anonymous types and Dynamic Lookup have very little use in 100% managed environment. It appears to me Microsoft has been adding these features for their own use mainly.

I can only speak for myself in here that I would never design anything that would require late binding features. I might be missing a point in both but I always thought abstraction can overcome the late binding challenges in managed environment.

In design point of view when one is developing a framework there are challenges that aren’t easy to solve. Some of these challenges can be solved by using the late binding technique. Since most systems being developed aren’t a framework or if there are then they are being used by an enterprise system it is possible to avoid using late binding approach in general.

What concerns me mostly is that developers might use a feature because is just there without spending more time to understand the problem on hand better. I think we developers need more caution reminders like your post.

I always said that in Software Development the hardest thing is to keep the logic of the code simple and manageable, something most take it lightly. For sure late binding technique makes everything far more difficult but not impossible.

# February 8, 2008 3:49 PM

wekempf said:

Great.  I'm not familiar with ASP.NET MVC (other than reading the hype in the blogs).  I can tell you that what you just showed is an abomination that has little to do with the anonymous type features in C#.  There is no anonymous type in the public interface.  However, based on your description, I must assume that in the implementation "defaults" is interrogated via reflection for certain properties.  The idea is to provide "named arguments" in C#, like you have in some languages, such as Python.  So, you could call it something like this:

Route r = new Route(url, new { Foo="bar" }, typeof(SomeRouteHandler));

That's just horrendous code.  Performance would be terrible.  You'd be better off using a Dictionary rather than an anonymous type, because you're relying on reflection.  You can't decry a language feature because someone chooses to horribly abuse it like this.  After all, you can't name a single language feature in any language that couldn't be abused by someone.

This isn't the purpose that anonymous types were created for.  It's also simply a bad idea, IMHO.

# February 8, 2008 3:53 PM

wekempf said:

I found an example of Route being used, here: forums.asp.net/.../2110762.aspx.

Again, I think this is simply misguided abuse.  Defaults should be strongly typed.  This is especially true if, as you suggest, reflection is being used to access the properties on the anonymous type.  This indicates a closed key/value mapping, and using a strongly typed object would vastly improve the performance here.

# February 8, 2008 4:03 PM

Jeffrey Palermo said:

@wekempf,

>You'd be better off using a Dictionary rather than an anonymous type, because you're relying on reflection.

Exactly my point.

>You can't decry a language feature because someone chooses to horribly abuse it like this

I would agree with that statement, and I would not decry anonymous types as a language feature even though it is being misused.

# February 8, 2008 4:04 PM

Kelly Leahy (Milliman) said:

Unless I misunderstood something here, Jeffrey is just saying he doesn't like the usage of anonymous types in these examples, not that he doesn't like the fact that these types exist in the language.

If I understood him correctly, I completely agree!  If you want to use anonymous types in the local scope to solve some problems that it's nice to have those language features for (rather than having to type a bunch of 'declaration' code), I'd say that's GREAT.  But, I don't think you should be passing those types somewhere else...

I think a nice feature would be if an anonymous type could automatically implement an interface, just by casting it (and having it check at compile time that it has the proper members).  That way, MVC could get the same benefits that they are looking for without the mess of having to create a 'real' type to implement the interface...

For instance, what if some interface was declared:

interface IRouteDefaults

{

 string param1 { get; set; }

 string param2 { get; set; }

 ...

}

and you could say:

new Route(url, new { param1 = "value1" } as IRouteDefaults, typeof(SomeRouteHandler));

and have the compiler automatically do:

1) implement IRouteDefaults on the temporary type

2) provide the default implementation for param2 (which is 'null' in this case)

3) provide the pointer to this interface to the constructor.

# February 8, 2008 5:16 PM

Peter Ritchie said:

They using Object for defaults and Defaults because they're leaking anonymous types from local scope?  Yuck, yuck, yuck, yuck, yuck.   Oh, did I say, yuck.  I recommend using anonymous types for short-lived (i.e. kept only to local scope) data.  That's potentially forcing it to be long-lived data.

# February 8, 2008 5:18 PM

sergiopereira said:

Amen. In a few months whoever came up with this great idea will be sorry - unless it's removed from the API, there's still time.

# February 8, 2008 8:54 PM

rjevans said:

I'm not against late binding in principle; it's hard to be like that given that most .Net 'data binding' is in effect 'late binding'.

The problem that I see with this usage is that it constitutes an 'opaque contract', in so far as the client has no immediate way of determining what expectations the API has.  

So in the extreme worst case, this could trigger significant trial and error as a client developer struggles to work out what really needs to be supplied to satisfy the (ambiguous) contract through (mis)reading the documentation and perhaps even being forced to debug through the target API calls.  

If an API does have contract expectations that go beyond what System.Object provides, then these need to be clearly communicated and should be easily verifiable prior to making API calls (ideally at compile time).

The only upside of this usage of System.Object is that it is somewhat better than the dreaded 'Name of Object' supplied via a String usage, e.g. string objName ="foo" to refer to the public object 'foo' in a call such as myClass.doSomethingWithObject("foo").  Which I'm sure is expressly intended to bedevil those of us who are prone to misstttyyyping occasionally (thanks be for Intellisense and the compiler, but sadly they don't work  inside strings <sigh>) .

# February 8, 2008 9:27 PM

Hadi Hariri said:

+1

# February 9, 2008 3:31 AM

» Daily Bits - February 9, 2008 Alvin Ashcraft’s Daily Geek Bits: Daily links, development, gadgets and raising rugrats. said:

Pingback from  &raquo; Daily Bits - February 9, 2008 Alvin Ashcraft&#8217;s Daily Geek Bits: Daily links, development, gadgets and raising rugrats.

# February 9, 2008 12:25 PM

Lance Fisher said:

Figuring out routing in ASP.NET MVC was as easy as firing up the reflector :P  But I don't mind the anonymous types in some other situations, even as parameters to methods.  Such as methods that create HTML where you already know the attributes well, and you usually only need/want a couple of them.  It does make it more difficult to pick up the framework though.

# February 10, 2008 3:02 AM

Jeffrey Palermo said:

@Lance,

The methods that create HTML (View helpers) do accepts html attributes, and, yes, the html attributes are well-defined, so it should be _really_ easy to create a simple object model around them.  Then, the object initializers feature allows you to create a syntactically similar line of code, but the method API is very clear and intuitive.

If my method is:

Html.Textbox(string, string, object), that's still confusing.  What the heck is "object"?  I'd rather see.

Html.Textbox(string, string, TextboxAttributes)

# February 10, 2008 12:06 PM

wekempf said:

Now that I understand what this API is doing, and more specifically, what the "Defaults" property/parameter (it's both) is for, this isn't as misguided as I originally thought.  Still the wrong solution, IMO, but I can understand it.

The "defaults" property has little meaning to the framework.  It's strictly a property bag or key/value collection that's used to provide default values for "page parameters" (for lack of a better term) when they aren't supplied in the URL.  I can even see how this usage could be optimized to be efficient, even though reflection would need to be used.  The meaning of the code isn't any less obvious when you use an anonymous object than it is when you use a Dictionary<string, object>.

That said, the only reason to be using the anonymous type is to simplify the calling code.  However, I don't find that to be a compelling reason to use an anonymous type here.  A DefaultValues dictionary type would add very little syntactically to the calling site.  The benefit here is minimal at best.  Since the Dictionary solution will perform the best here, I don't agree with the use of the anonymous type.

# February 11, 2008 8:41 AM

About Jeffrey Palermo

Jeffrey Palermo is a software management consultant and the CTO of Headspring Systems in Austin, TX. Jeffrey specializes in Agile coaching and helps companies double the productivity of software teams. Jeffrey is an MCSD.Net , Microsoft MVP, Certified Scrummaster, Austin .Net User Group leader, AgileAustin board member, INETA speaker, INETA Membership Mentor, Christian, husband, father, motorcyclist, Eagle Scout, U.S. Army Veteran, and Texas A&M University graduate. Check out Devlicio.us!

This Blog

Syndication

News

Headspring Systems

View Jeffrey Palermo's profile on LinkedIn

See my new blog at .jeffreypalermo.com