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 (51)

  1. EricLippert says:

    HA HA HA HA HA. I crack myself up.

    This joke is not original to me of course; it’s been making the rounds of programming web sites for a couple years now. If anyone knows the origin of it, I’d be happy to give credit where it’s due.

  2. Chris B says:

    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.

  3. Anthony P says:

    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.

  4. Keith says:

    A whileGoesTo keyword would have probably been better, but its probably reserved by VB

  5. Mike Greger says:

    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

  6. Anthony P says:

    @Mike, all me to present the "is run over by" operator, <=–

  7. Joey says:

    So can we expect the ==> operator in future versions of C# that incements by 2? This would be a very handy operator, too. tia 😉

  8. Pavel Minaev says:

    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.

  9. Alan Ou says:

    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;

    }

  10. Anthony P says:

    When do  you guys put in the while else loop?

    while (true)

       if (false)

           break;

    else

       Console.WriteLine("blah");

  11. trevortosello@hotmail.com says:

    hilarious.

  12. termserv says:

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

  13. Clinton Pierce says:

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

  14. arnshea says:

    Happy April Fool’s day!

    Good one, had me going there for a few seconds!  God I hope that godawful feature, sugar for the prefix and postfix operators, is NEVER implemented.  But if it is at least leave it out of VB.  LOL

    It is implemented. Try it. (Hint: it is not a syntactic sugar for the prefix and postfix operators.) — Eric

  15. Rik Hemsley says:

    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!

  16. Daniel says:

    Any plans to implement the "dagger" operator?

    Read "x stabs y"

           int x = 10;

           int y = 5;

           while (x ++!=– y)

           {

               break;

           }

  17. James Curran says:

    So, when you say "*Today* I am announcing" …….

  18. arnshea says:

    Ahh, lol, whitespace is for humans eh?  Mostly anyways.  :)

  19. Pavel Minaev says:

    Also, in the continuing spirit of TheDailyWTF, I would also like to request the "definitely" operator, which wraps any boolean expression, and evaluates it twice times (just to be sure it’s really true). E.g.

      if (definitely(foo != null)) { …. }

    That’d also be some sweet syntactic sugar for dealing with those pesky race condition related bugs, writing thread-safe singletons etc – if it crashes, well, just add another "definitely". To make it easier, allow them to be chained without extra parens:

     if (definitely definitely definitely (foo != null)) {

        // NOTE: if code crashes here, add another "definitely" above!

        foo.Bar();

     }

  20. Pavel Minaev says:

    @James:

    Why not follow Eric’s advice, and try it on your local compiler version?

  21. DotNetter says:

    To be in parity with:

           for (int i = 0; i < 10; i++)

    How about:

           while (int x = 10; x–>0)

  22. John says:

    I wish more large companies allowed their employees to have a sense of humor.  Kudos!

  23. Stuart says:

    @Pavel:

    public class definitely {

     private bool Val;

     public implicit operator bool(definitely def) {

       return def.Val;

     }

     public explicit operator definitely(bool val) {

       return new definitely() {Val = val};

     }

    }

     if ((definitely) (definitely) (definitely) (foo != null)) {

       // NOTE: if code crashes here, add another "definitely" above!

       foo.Bar();

     }

  24. Pavel Minaev says:

    @Stuart: that won’t do the trick, since the expression (foo != null) will only be evaluated once, and then the _computed result_ of that expression will be repeatedly re-evaluated. The crucial part of the concept – that which makes it so valuable – is that the entire parenthesized expression itself is recomputed every time.

    I don’t think this is doable as a library solution using existing C# means – though by all means go ahead and prove me wrong, if possible.

  25. Thomas Levesque says:

    @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();

       }

  26. PiersH says:

    how about adding the ‘??=’ operator  ‘last-minute’ ? are there any other binary operators missing their assignment equivalents?

  27. Pita.O says:

    I thought this was an April fool’s joke until I tried it on vs2010. works fairly ok for integers, though. the ‘tends-to" operator is always a decrementing operator, such that

    x—> y where y is larger than x does not yield expected results.

    With the double data type, it goes completely crazy.

    The following code will produce a last output of 2.7. Go figure!

    var x = 50.7d;

    while (x– > 3.5)

    {

         Console.WriteLine(x);

    }

  28. Shasur says:

    Thanks Eric. Amazed at the Float version of it!!

  29. Mark Knell says:

    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.

  30. CuttingEdge says:

    You scared the shit out of me. Glad it is an April fools joke :-)

  31. izobr says:

    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

  32. Jaywalker says:

    How much extra hours your team had to work to implement this really _useful_ feature? :)

  33. Mike Synnott says:

    This is antastic news. The key between ‘D’ and ‘G’ on my keyboard doesn’t work, so I’ve never been able to write incrementing loops – you know; the ones that use that keyword that begins with the key between ‘D’ and ‘G’. These new operators will probably save my coding career.

    God bless you Microsot.

  34. Well, I may have preferred the ‘..’ as known to powershell:

    (0..20) | % { Write-Host "I am $_" }

  35. v.reshetnikov@gmail.com says:

    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");

    }

    }

  36. DevinB says:

    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?

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

  38. Of course these operators should NOT be added until the "!!!" operator is in-place (used when programmer bangs ghead three times due to foolishness!!!)

  39. Tom Smykowsky says:

    while (Microsoft –> Hell)

    {

        // TODO:

    }

  40. freda says:

    /// <summary>

    /// –> => > >> >>> ! <<< << < <= <–

    /// </summary>

  41. Eugene says:

    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 :)

  42. Eugene says:

    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#.

  43. TechNeilogy says:

    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.

  44. arjuns says:

    That is crazy, I was so flown to the article. Never noticing x –> 0 is same as x– > 0.

  45. Pavel Minaev says:

    > 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)?

  46. You had me there.. until I read the last paragraph. But yes, this is a nice trick to play on people.

    Arun

  47. LeakyHandle says:

    Some Last-Minute New C# 4.0 Features –> ha ha ha, but nice joke :)

  48. 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!

  49. Zpektrum says:

    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

    😉

  50. Leo G says:

    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.

  51. DavidN says:

    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