An Unfair World of Tuples, Anons., var and auto

It all began when I wanted to return more than one value from one of the methods. Although my attempts ended futile, it was fun exploring and musing how things could have been.

There are at least a couple of options to return multiple values from a method:-

  1. return an instance of a class that holds the values
  2. return a tuple

Well, both the options are nothing unusual; not extraordinary either. If the method always returns closely/directly related values (say employee details), a class would be the default choice. Otherwise, if the method returns discrete or loosely related values, a tuple would be appropriate. In the latter case, one could still define a class with a really clumsy name (if naming is not something of importance to the person or team). But how many would you create?

I was looking at something better - an anonymous type 1. Why? Because I did not want a class, and my values being discrete, I did not want to access the return values as Item0, Item1 etc. (on the calling side). Looks erghhh! I wanted the client code to be type safe and explicit when accessing the return values … without declaring a clumsy-named class. Anonymous types are a great way to do that. It is exactly how LINQ query makes elegant use of anonymous types to return strongly typed projections of the queried data. All good except it is not possible to return an anonymous type from a method. Duh!

For instance, we would not be able to define something like this:-

public var GiveMeAnonType(String symbol, double amount) {
    return new { Symbol = symbol, Amount = amount };
}

It is not that you cannot have a return statement with an anonymous type in a method. You can. But how do we declare the return type of the function? It would have been marvelous to name it using var. The var keyword is scoped and does not transcend declaration boundaries (methods). The C# design team seems to have purposely enforced such a limitation. To what purpose, that I am not aware of.

That said, let us explore ways to circumvent this limitation and try return an anonymous type from a function.

object: The method could return an object in place of var. Hopefully no language rule or restriction could break that. Although we overcome the limitation, we don’t solve the purpose. On the calling side, we would have to play gimmicks to access the properties of the actual anonymous type returned:-

 public object GiveMeAnonType(String symbol, double amount)
 {
     return new { Symbol = symbol, Amount = amount };
 }

 public void CallingMethod()
 {
     object result = GiveMeAnonType("$", 44.99);
     var wow = Cast(result, new { Symbol = "", Amount = 0.0 });
     // wow is now a compile time type safe! Oh, don't look at
     // the ugly second parameter in the Cast call.
 }

 private T Cast(object obj, T type)
 {
     return (T) obj;
 }

Also, note that if it weren’t an anonymous type, we wouldn’t need the second parameter (T type) in the Cast<T> method. If you don’t wish to push further, the above trick solves the purpose (to a certain extent). Except the code is not really fluid, and they say, Don’t help the compiler. In this case, the compiler looks like a broken robot, and we are soldering a disconnect so that it dances to our tune. Let me tell you why it is not fluid. First, if the compiler folks were to change the strategy of reusing the compiler generated type for the anonymous type declaration, we are broke. Second, if GiveMeAnonType were to change the parameters of the anonymous type, agreed that we would get compilation errors in the CallingMethod but that’s when our soldering wears out.

dynamic: Well, that seems to be a smart option:-

public dynamic GiveMeAnonType(String symbol, double amount) {
    return new { Symbol = symbol, Amount = amount };
}

public void CallingMethod()
{
    dynamic wow = GiveMeAnonType("$", 44.99);
    Console.WriteLine("{0}, {1}", wow.Symbol, wow.Amount); // Cool!
}

That looks really clean and beautiful. Beauty is skin deep! With dynamic, we lose compile-time type safety.

Ignoring performance constraints, given a choice I would go for dynamic because at least I don’t have to solder with the Cast method and the explicit dummy and match anonymous type as the second parameter.

Scenario

Imagine you are writing a web service that returns, let us say, employee information. Only that it returns what was asked for. For instance, if only the employee’s name and designation was requested then that’s what would be returned. The point is although we know the entire gamut of employee details, what would be returned, subset or whole, is determined at runtime.

In such a case, we would neither want to create a combinatorial explosion of classes EmployeeWithXXXProperties class nor do we want to twiddle with Dictionary (or Hashmap sort of things). Yes, you are thinking dynamic. But we discussed it before - type safety and all that. I am thinking anonymous types!

The commission

Typically, somewhere in one of the methods in the call graph for the above service call, we would be gathering the necessary properties to be returned back. It is possible that these properties might have to be massaged a bit before sending it out. For instance, imagine Customer instead of Employee, and we would want to mask the credit card number; something like that. That means even our own code/infrastructure would have to access these properties in an explicit type safe way. It is not just one place where the ugly detail of gathering the Employee properties (into a HashMap or class) would be hidden.

Now you might also counter me back - Even if there was a way to create and return anonymous types to solve this problem, parts of the code up in the call graph might not be able to access one of the properties (anon.Name) if that property is not part of the anonymous type returned. For instance, if the method did not return, say Designation, as part of the anonymous type, and if the caller was accessing it as anon.Designation, it would throw compilation error! Excellent observation. Let me explain.

There are several things at play here. Let us analyze with a couple of cases:

Now you are awake, and asking, OK, what if other parts of the code need to access one of these properties (anon.Property)? Yes, there are options:

However, if asked to choose, I would go with option #1, and let the gatherer deal with it. That way, the massaging is a low-level detail of this sequence. I think it is easier and better to reason our code when it is typed; massageData(Employee).

Utopia

Let us assume if C# were to allow returning anonymous types with the var keyword (or another keyword), imagine how fluid the code would be. The compiler would be aware of the (anonymous) type and the type information would flow without friction and noise. Yes, there will be rules and restrictions around such a feature. Yes, there are people who wouldn’t understand the purpose of the feature and start using anonymous types all over. Some will fall in love with the feature that their code will no more have named types as classes or structs. But that is not good enough reason to experience this feature in reality. It might as well prove to be a better alternative to Tuples.

Unlike C++, where tuple is defined using variadic templates (πŸ‘ πŸ‘ πŸ‘), most other languages including C# explicitly declare distinct class overloads distinguished by the number of generic parameters. πŸ‘Ž

Meanwhile Elsewhere

Usually, C++ has something in stock for such odd problems2. The matter is you should be willing to look back. And the difference is the syntax is either clumsy or crazy. Many concepts available in the form of refined constructs in current day languages would available in crude forms. If not, it would be available in a very limited form.

So let us see if we can return anonymous types in C++, limited or brief nevertheless. In C++, we cannot create anonymous types the way we do in C#. We do can create anonymous types, though … as lambdas.

auto count = count_if(numbers.begin(), numbers.end(), [](int x) {
   return x > 5;
});

I am sure you know where lambda is in the above code. The C++ compiler creates an anonymous class for the lambda as functor.

So we proved we can create an anonymous class in C++. Let us now return one.

auto anon = [](int x) {
    return x * x;
}

auto GiveMeAnon() -> decltype(anon) {
    return anon;
}

void main() {
    auto anon = GiveMeAnon();
    auto r = anon(5);
    cout << r << endl; // prints 25;
}

I know you feel a leech on your back.

That’s where it all ends in C++, just when we proved that we can return anonymous types. Yes, you pointed out that we are not actually returning an anonymous type constructed right at the return site. But hey, we at least got something.

auto is more or less var with a syntactic difference that it can be used as return type place holder for functions. However, the decltype addendum is mandatory 3.

try ... finally

It is not uncommon these days that part or whole of an application is based on data passing between the server and the client(s), and the data is dynamic that it wouldn’t be worthwhile defining or at least hand code the data model classes. Creating classes/types on the fly and passing them around is not new in JavaScript. It is time for languages like C# to invent a way to create, pass around and work with such types - anonymous yet compile-time type-safe.

So here is a challenge, obviously to the, C# team if they can crack this thing out - anonymous types on the fly. Yes, there are challenges, corner cases and all that. Remember a few years back, there was no yield, no async-await etc. We have them now. I believe we should be able to invent something around anonymous types.

State of Bliss

Ignorance is bliss and is itself a state of bliss. Java programmers wouldn’t mind or care about any or all of what we discussed. They have got the for loop for all problems. πŸ˜†

I was trying all this with Java, and finally ended up using tuples.


  1. The term anonymous types refers to the feature in C# while anonymous class refers to another feature in Java. They are similar and distinct in their own ways. However, in this post, the terms could have been used interchangeably in the context of C#. ↩︎

  2. See Also Think Currying, Extension Methods – A Polished C++ Feature ↩︎

  3. The intricate details of auto and decltype are beyond the scope of this post. ↩︎