Wednesday, May 27, 2009

Gloating just a little bit: new meaning of auto keyword in C++0x

I know this blog has been kind of dead in the water for over a year now (strangely I made only two posts since I met my wife! makes me want to go hmmmm.... but of course I'll refrain myself ;) (yes, the big, huge, humongous personal news is that I got married to the WonderWoman... but I bet that everybody here, if there is anyone left... or to be more precise if there was anyone in the first place!... thinks that his/hers better half is *the* WonderBetterHalf, so let's just leave it at that :)

Warning, unless you are a C++ developer this whole post won't mean much to you... Sorry about that. The next post will be about things we are doing in ApexSQL Log and ApexSQL Recover.

Anyway, since it's been such a long time, I thought that I should blog about something that I have been waiting for... at least since 2002 when I first publicly suggested it in now-defunct C/C++ User's Journal (a.k.a. CUJ.) I wrote in 2002 September issue of CUJ in We Have Mail section... well, it's too long to write it here but this is the meat of it:

"...my favorite pet idea for a core language extension: a keyword for an unknown type. It would work exactly like typeof extension, but without taking any parameters..."

After 7 years of waiting today I installed Visual Studio 2010 Beta 1 and I finally had a chance to run my first app with just such language extension from the upcoming C++0x language standard! :) I have known for quite some time that this extension has been officially introduced into the draft of the standard but this is the first time that I had a chance to try it (more on the upcoming standard can be read here.

Anyway, here's the example I used (a bit uninspired but I started from incomplete example I used in my email to CUJ so...)

#include <iostream>
#include <vector>

template<class T>
void process(const T& v)
{
for(auto it = v.begin(); it != v.end(); ++it)
{
std::cout << *it << std::endl;
}

}

int main(int argc, char* argv[])
{

std::vector<int> v;

v.push_back(1);
v.push_back(2);
v.push_back(3);

process(v);

return 0;
}

This spits out:
1
2
3

Marvelous! For those that don't see much value in this I will quote another example that I put forward in that original email:

"The previous example is rather simple, so advantage is not enough to warrant a core language extension. However, consider this example (adapted slightly from
The C++ Standard Library: A Tutorial and Reference by Nicolai M. Josuttis, page 306):

pos = find_if(coll.begin(), coll.end(), std::not1(std::bind2nd(std::modulus<int>
(),2)));

Imagine that we want to make a variable of the type returned by the std::not1(std::bind2nd(std::modulus<int>
(),2)) expression for further reuse..."

Then I went on to provide the exact type of this expression. Here it is for your reading pleasure:


std::unary_negate<std::binder2nd<std::modulus<int>>>


What a cute little type... NOT! Luckily I never had to use it in real life development and hopefully I never will but I have used much worse and, I'm sorry to say, most of my own making. Even though BOOST_FOREACH solved most of for loop direct references to STL iterators, this will be a welcome relief from the tedium of not only writing things like
:

std::map
<SomeTraitsStructure::SomeKey,SomeTraitsStructure::SomeItem>::iterator it = m_objectsMap.begin();

but also from looking at them. Instead, C++0x standard committee gave us:


auto it = m_objectsMap.begin();


I for one am very grateful for that! I can't wait for Visual Studio 2010 to be officially released so that I can get rid of all the verbose cruft.


Just to wrap up:
  1. Andrew Koenig answered that email on the pages of CUJ but at the time he had little hope that such an extension would be adopted. I'm very glad that the committee found a way to bring this forward.
  2. In no way do I think that I was the first to come up with this or some such nonsense like that. In fact I believe that it's a rather obvious extension (after all compiler in a strong typed language as C++ compiler already knows everything that it needs to know to make this work.) But I'm glad that I made that suggestion and that it's the earliest public reference that I know of so... I'm gloating today... just a little bit :)
  3. I'm quite aware of typedefs and have become equally tired of them in this context. Some would call it losing my religion but it's just too much for me. I think that the worst part is the naming: how do you name type of iterator on the map like the one I used above? SomeTraitsStructureKeyItemMapIterator? And all that for just one function... no thanks, I know I will love "auto" if nothing else just for replacing all such typedefs (have I already mentioned that BOOST_FOREACH has really helped the thing here?)
  4. The same "auto" feature has been introduced in C# in version 3.0: var keyword. I read here that MS warned about using "var" everywhere in the source code as it, purportedly, decreases readability of it and that it should be used only with anonymous types. I agree with this advice for C++ but to a degree. I wouldn't type:
auto i = 10;

I wouldn't use it even to shorthand something like "boost::shared_ptr<>" usage. We make a typedef once for every type that needs it and then use just that. I would keep that usage: seeing MyTypePtr is better than just "auto". But for types like we have in the examples above, "auto" keyword (or, to be precise, its new meaning) is really great. However, the real power of "auto" keyword in C++ will show itself in generic programming where today types have to follow naming conventions (in fact, IIRC, the original Koenig and Moo article was about type naming conventions.) In C# generic programing is... damaged goods. It's useful but it's been lobotomized on purpose by its designers so it never approaches usefulness of C++ generic programming model (nor it's complexity and trickiness - that was the whole point.) So yeah, "var" in C# has to be treated differently than "auto" in C++ even if they are essentially the same.


Whew.... Ok, that's all for this year folks ;)