Some Last-Minute New C# 4.0 Features

As I’m sure you know by now, we are done implementing C# 4. We’ve added support for interoperability with dynamic languages and legacy object models, named and optional parameters, the ability to “link” against interfaces from a Primary Interop Assembly, and my favourite feature, covariance and contravariance of interface and delegate types.

Now, sometimes we manage to find time in the schedule to fit in small additional features that do not directly align with the larger “theme” of the release, but are useful features in their own right. In C# 3 we were all about LINQ features, but we did manage to also sneak in auto-properties and partial methods, neither of which directly supported our LINQ mission. But because they were clearly useful and relatively easy to design, implement, test and document, we got them in there.

Today I am announcing that we managed to get two additional operators into C# 4 that we have not hitherto announced: the “goes to” operator , written --> and the “is approached by” operator, written <--. In fact, we managed to get both of them into the last community preview, so if you have the CTP build, you can try them out today! (As you probably know, we do not like to ship features without running them by the community first.)

Here are examples of both operators:

int x = 10;
// this is read "while x goes to zero"
while (x --> 0)
{
Console.WriteLine("x = {0}", x);
}

As you can see, this does exactly what you’d expect: x becomes 9, 8, 7, and so on, as it “goes to zero”. Our awesome compiler architect Neal heard via his contacts in the industry that the latest version of Java has this operator; wanting to maintain our massive lead in language features over Java, of course we worked overtime to deliver its benefits to our valued C# developer community.

Shortly thereafter, our awesome language specification manager Mads realized that we could generalize this to the inverse operator, the “is approached by" operator. We therefore implemented it too:

int x = 10;
// this is read "while zero is approached by x"
while (0 <-- x)
{
Console.WriteLine("x = {0}", x);
}

And as you can see again, x takes on each value as it approaches zero. The exact semantics of this operator are subtly different than the goes-to operator, but I’ll describe the differences in a later post.

Pretty neat, eh? I am sure you guys can think of all sorts of wonderful uses for these new operators. The time pressure was really hard for this one, but they came through.

Finally, I know we've said that we want to maintain language-feature parity between C# and Visual Basic; unfortunately we were unable to get these operators into VB this time around. Perhaps in a future version.

UPDATE: Happy April Fool's Day everyone. For those of you who I fooled -- including at least one tester on the C# QA team, ha ha ha ! -- of course we are not announcing new operators the day before we ship C# 4.0.  "while (x --> 0)" is the same as "while( x--   >   0 )" which is of course perfectly legal and sensible code. This is an old joke; it works in any language with a "--" decrement operator.

Comments

  • Anonymous
    March 15, 2010
    The comment has been removed

  • Anonymous
    March 31, 2010
    Never seen that before.  If everyone I know didn't have Visual Studio's "auto-format" feature enabled, I'd have some fun showing it off.

  • Anonymous
    March 31, 2010
    I was about to ask if something like that would be syntactic sugar for a for loop while (x --> 0) would be for (int i = x; i >= 0; i--) Then, of course, I click on comments.

  • Anonymous
    March 31, 2010
    A whileGoesTo keyword would have probably been better, but its probably reserved by VB

  • Anonymous
    March 31, 2010
    0 <-- x  performs one less iteration than x --> 0. Will this be fixed in C# 5 ? I already have critical production code which depends on this new feature. :) As I told you, there are subtle semantic differences between the two operators. That's one of them. :) -- Eric

  • Anonymous
    April 01, 2010
    @Mike, all me to present the "is run over by" operator, <=--

  • Anonymous
    April 01, 2010
    So can we expect the ==> operator in future versions of C# that incements by 2? This would be a very handy operator, too. tia ;-)

  • Anonymous
    April 01, 2010
    Eric, It was brought to my attention that the draft standard for C++11 also includes this new pair of operators. It must be an oft-requested feature! Anyway, I've noticed that the C++ version of the "is approached by" operator is more flexible in that it allows steps other than 1 with a very straightforward syntax modification; e.g.:   while (0 <---- x); // step of 2   while (0 <------ x); // step of 23 Personally, I find it to be some brilliant language design, in excellent tradition of SHORT SHORT ... INTEGER and LONG LONG ... INTEGER of Algol-68. Are there plans to include this into C# for the sake of feature parity? In fact, I urge you to do that before Java does (they are also missing it, so far as I can see), to gain a competitive edge. It could just be the final nail in that coffin - the other significant one, of course, being that C# uses short and concise "bool" over Java's long-winded "boolean", resulting in significant increase of programmers' productivity.

  • Anonymous
    April 01, 2010
    I tried to make x start at 0 and "go to" 10 and got unexpected results. Compiler bug? I was able to work around by overloading a few of the operators for "int" to increment instead of decrement. I know that will break some existing code so I conditioned the custom operator on a global variable (wrapped in locks for thread safety) to enable the custom behavior. I think the new code is perfectly readable and really shows off the strengths and flexability of this new operator (also Java can't do it because it doesn't allow user defined operator overloading). static int operator--(ref int value) {    int result = value;    if( g_fGoingUp )        value = value+1;    else        value = value--1;    return result; } static bool operator>(int value1, int value2) {    if( g_fGoingUp )        return value1 < value2;    else        return value1 > value2; } lock(g_GotoLock) {    g_fGoingUp = true;    int x = 0;    while( x --> 10 )        Console.WriteLine("x = {0}", x);    g_fGoingUp = false; }

  • Anonymous
    April 01, 2010
    When do  you guys put in the while else loop? while (true)    if (false)        break; else    Console.WriteLine("blah");

  • Anonymous
    April 01, 2010
    hilarious.

  • Anonymous
    April 01, 2010
    I tried this with x declared as a float, and ended up with what seems like an infinite loop.  Am I doing something wrong?

  • Anonymous
    April 01, 2010
    @termserv:  For X as a float, you needed the approximation version of goes to/approached by:  while(0 <~~ X)  { }

  • Anonymous
    April 01, 2010
    The comment has been removed

  • Anonymous
    April 01, 2010
    I would have preferred istrue and isfalse operators. You've no idea how much code I see that looks like: if (userLoggedIn == true) ... or if (fileExists == false) ... Of course, like me, you wonder why these aren't double checked. If we had the aforementioned operators, we could write: if (istrue(userLoggedIn == true)) and if (istrue(fileExists == false)) Much better. And no need for unit tests!

  • Anonymous
    April 01, 2010
    Any plans to implement the "dagger" operator? Read "x stabs y"        int x = 10;        int y = 5;        while (x ++!=-- y)        {            break;        }

  • Anonymous
    April 01, 2010
    So, when you say "Today I am announcing" .......

  • Anonymous
    April 01, 2010
    Ahh, lol, whitespace is for humans eh?  Mostly anyways.  :)

  • Anonymous
    April 01, 2010
    The comment has been removed

  • Anonymous
    April 01, 2010
    @James: Why not follow Eric's advice, and try it on your local compiler version?

  • Anonymous
    April 01, 2010
    To be in parity with:        for (int i = 0; i < 10; i++) How about:        while (int x = 10; x-->0)

  • Anonymous
    April 01, 2010
    I wish more large companies allowed their employees to have a sense of humor.  Kudos!

  • Anonymous
    April 01, 2010
    The comment has been removed

  • Anonymous
    April 01, 2010
    The comment has been removed

  • Anonymous
    April 01, 2010
    @Pavel: Well, you could make it work with just a small change in the syntax :    public class definitely    {        private Func<bool> _test;        public static implicit operator bool(definitely def)        {            return def._test();        }        public static explicit operator definitely(Func<bool> test)        {            return new definitely { _test = test };        }    } To use it :     if ((definitely) (definitely) (definitely) (() => foo != null))    {        foo.Bar();    }

  • Anonymous
    April 01, 2010
    how about adding the '??=' operator  'last-minute' ? are there any other binary operators missing their assignment equivalents?

  • Anonymous
    April 01, 2010
    The comment has been removed

  • Anonymous
    April 01, 2010
    Thanks Eric. Amazed at the Float version of it!!

  • Anonymous
    April 01, 2010
    If there's time for changes, I'd like to report a bug.  I know you're pressed for time so I've already written a unit test that demonstrates the problem:        [TestMethod]        public void AssertShift()        {            int x = 1 << 1;            int y = 1 << 32;            Assert.IsTrue(x < y);        } This fails in VS2008 using .NET 3.5, and although I had to uninstall the CTP recently, I believe it fails there, too. I know you're probably busy as heck but I wrote it up in the hope that today is the last day you'll be considering this sort of submission before RTM.

  • Anonymous
    April 01, 2010
    The comment has been removed

  • Anonymous
    April 01, 2010
    Besides joking, a range operator may be quite useful. I mean ".." (two dots) may be shortcut to Enumerable.Range() method. foreach(var x in 0..100)
    {
       Console.WriteLine(x);
    } var notPrimes = 
       from x in 2..10
       from y in x..10
       select x*y; var primes = (2..100).Except(notPrimes); And of course number of dots can indicate step size: foreach(var x in 0....100) // increment by 3
    {
       Console.WriteLine(x);
    } :-) We actually did implement a similar operator as a prototype; it would have only worked in the "watch window" in the debugger. The idea was that you could say "show me the contents of this array from 10 to 20". I'm not sure why we never went ahead and turned it into a real feature; this was before my time. -- Eric

  • Anonymous
    April 01, 2010
    How much extra hours your team had to work to implement this really useful feature? :)

  • Anonymous
    April 01, 2010
    The comment has been removed

  • Anonymous
    April 01, 2010
    Well, I may have preferred the '..' as known to powershell: (0..20) | % { Write-Host "I am $_" }

  • Anonymous
    April 01, 2010
    Eric, why have not you blogged about another very cool new feature - embedded URLs? using System; class C { static void Main() {  http://www.microsoft.com  Console.WriteLine("Go"); } }

  • Anonymous
    April 01, 2010
    Are we certain that you have examine all the possible security and runtime implications? int jd = 21; while(jd --> vegas) {   //"This item is obfuscated and can not be translated" } How will we know what the value is once we get jd back?

  • Anonymous
    April 02, 2010
    F# has the ability to create lists in steps [5..10].  I know its different, but useful.  Mimics the while loop "list creation" here.

  • Anonymous
    April 02, 2010
    The comment has been removed

  • Anonymous
    April 02, 2010
    while (Microsoft --> Hell) {     // TODO: }

  • Anonymous
    April 02, 2010
    /// <summary> /// --> => > >> >>> ! <<< << < <= <-- /// </summary>

  • Anonymous
    April 02, 2010
    Genious! Lets create fixed like in java, multimple inharitance like in c++. Const function like in c++; Preprocessors!!! I need preprocessor like in c++! Good joke :)

  • Anonymous
    April 02, 2010
    BTW, operator = ability to specify operators in interface. Common interface for all numerical types. Matrix type. Extends System.Math to use Complex type, etc. All those stuff allows  to use C# in math. Instead of mathlab, mathematica or maple. I very sad that C++ is more usefull than c#.

  • Anonymous
    April 04, 2010
    I love it.  This is the kind of humor that was typical of C language programming in the "old days."  With this C# example, I feel a tear of nostalgia and a ray of hope for the future.

  • Anonymous
    April 04, 2010
    The comment has been removed

  • Anonymous
    April 05, 2010
    > We actually did implement a similar operator as a prototype; it would have only worked in the "watch window" in the debugger. The idea was that you could say "show me the contents of this array from 10 to 20". I'm not sure why we never went ahead and turned it into a real feature; this was before my time. Maybe because the functionality is still available in form of Enumerable.Skip/Take/ToArray, which can all be evaluated just fine in Watch (except when stuck in native code during mixed debugging)?

  • Anonymous
    April 06, 2010
    You had me there.. until I read the last paragraph. But yes, this is a nice trick to play on people. Arun

  • Anonymous
    April 06, 2010
    Some Last-Minute New C# 4.0 Features --> ha ha ha, but nice joke :)

  • Anonymous
    April 06, 2010
    The minute I saw the title of the post, I looked at the date and I knew without reading the post where this is leading!

  • Anonymous
    April 07, 2010
    Nice one!! That made me remind of an old (ancient, really ancient) joke. Tell me if you can "compile" this sentence: IF IF THEN THEN = ELSE ELSE ELSE = THEN ;)

  • Anonymous
    April 10, 2010
    It would be helpful to me if x -->!> y meant x approaches y VERY fast, so that I could write software that performed well on machines with fewer resources. In the mean time I will resort to avoiding bubble sort and the like.

  • Anonymous
    April 14, 2010
    Long ago in the days of ‘goto’ it was proposed that we should have a ‘comefrom’ which would be very helpful with debugging. I gather that we might have that now. Not in C#. But you can do comefrom in Python. -- Eric