88

I was looking at some example C# code, and noticed that one example wrapped the return in ()'s.

I've always just done:

return myRV;

Is there a difference doing:

return (myRV);
H.B.
  • 166,899
  • 29
  • 327
  • 400
chris
  • 36,094
  • 53
  • 157
  • 237

4 Answers4

230

UPDATE: This question was the subject of my blog on 12 April 2010. Thanks for the amusing question!

In practice, there is no difference.

In theory there could be a difference. There are three interesting points in the C# specification where this could present a difference.

First, conversion of anonymous functions to delegate types and expression trees. Consider the following:

Func<int> F1() { return ()=>1; }
Func<int> F2() { return (()=>1); }

F1 is clearly legal. Is F2? Technically, no. The spec says in section 6.5 that there is a conversion from a lambda expression to a compatible delegate type. Is that a lambda expression? No. It's a parenthesized expression that contains a lambda expression.

The Visual C# compiler makes a small spec violation here and discards the parenthesis for you.

Second:

int M() { return 1; }
Func<int> F3() { return M; }
Func<int> F4() { return (M); }

F3 is legal. Is F4? No. Section 7.5.3 states that a parenthesized expression may not contain a method group. Again, for your convenience we violate the specification and allow the conversion.

Third:

enum E { None }
E F5() { return 0; }
E F6() { return (0); }

F5 is legal. Is F6? No. The spec states that there is a conversion from the literal zero to any enumerated type. "(0)" is not the literal zero, it is a parenthesis followed by the literal zero, followed by a parenthesis. We violate the specification here and actually allow any compile time constant expression equal to zero, and not just literal zero.

So in every case, we allow you to get away with it, even though technically doing so is illegal.

Callum Watkins
  • 2,844
  • 4
  • 29
  • 49
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 2
    @Eric Lippert: Why the spec violations? I see that you say for convenience but how do you weigh the balance of violating the spec versus being convenient? Was it a bug that became a feature for convenience? :-) – jason Feb 02 '10 at 20:53
  • I think the last word you meant to be *illegal*? – Dan Tao Feb 02 '10 at 21:00
  • 12
    @Jason: I believe the spec violations in the first two cases are simply errors that were never caught. The initial binding pass historically has been very aggressive about prematurely optimizing expressions, and one of the consequences of that is that parentheses are thrown away very early, earlier than they ought to be. In pretty much every case, all this does is makes programs that are intuitively obvious work the way they ought to, so I'm not very worried about it. Analysis of the third case is here: http://blogs.msdn.com/ericlippert/archive/2006/03/28/the-root-of-all-evil-part-one.aspx – Eric Lippert Feb 02 '10 at 21:25
  • 6
    In theory, in practice, there *is* a difference (I'm not sure if Mono allows these 3 cases, and don't know of any other C# compilers, so there may or may not be a difference in practice in practice). Violating the C# spec means your code won't be fully portable. Some C# compilers may, unlike Visual C#, not violate the spec in those particular cases. – Brian Feb 03 '10 at 15:56
  • 1
    The blog post is now live: http://blogs.msdn.com/ericlippert/archive/2010/04/12/ignoring-parentheses.aspx – Daniel Daranas Apr 12 '10 at 16:17
  • 5
    Damn, I'm almost ashamed when I read Lippert insights... I don't think I have knowledge about any subject even close to how much he has about C#. – Bruno Brant Apr 12 '10 at 17:52
  • 18
    @Bruno: All it takes is about eight or ten thousand hours of study of a given subject and you too can be an expert on it. That's easily doable in four years of full-time work. – Eric Lippert Apr 12 '10 at 20:24
  • 3
    @Eric, those are ~80 hour weeks! Take a vacation. – Anthony Pegram Apr 12 '10 at 20:53
  • 5
    @Anthony: 8 hours per day x 5 days per week x 50 weeks per year = 2000 hours per year. 8000 hours / 2000 hours per year = 4 years. Where are you getting 80 hour weeks from in there? – Eric Lippert Apr 12 '10 at 21:54
  • 3
    @Eric, I'm getting that number from pure failure, that's where. :( I'm usually good at mental math, but not today. I blame getting old. – Anthony Pegram Apr 12 '10 at 23:05
  • 32
    @Anthony: When I do that I just tell people that my degree is in *mathematics*, not *arithmetic*. – Eric Lippert Apr 12 '10 at 23:34
  • 4
    @Eric: for a second there, i read that as 8 or 10 thousand *years* of study! :) – RCIX Apr 13 '10 at 00:25
  • My heart would totally go for "Don't Violate The Specs Under Any Circumstances". Mainstream languages usually have more than one compiler -we already have mono and MS csc- and this makes specs verification a very necessary facet. This is the only way we can have true portability. The worse part is, once you make such a mistake, you can't revert it because this might break others' code. Bad – Ahmed Apr 13 '10 at 10:40
  • 7
    In theory, practice and theory are the same but, in pratice they never are. – Sayed Ibrahim Hashimi Sep 23 '10 at 05:46
  • 1
    It's unfortunate that the compilers don't follow the spec. But I checked and Mono (gmcs 2.4.2.3) does allow all 6. – Matthew Flaschen Nov 26 '10 at 18:49
  • 1
    That third remark explains a problem that baffled me where an integer matched an overload that took an enum instead of being boxed and passed as an object. "The spec states that there is a conversion from the literal zero to any enumerated type" What's the explanation for this? Why, if any, just zero? – John Leidegren Jan 03 '11 at 14:48
  • 2
    @John: (1) because you need to be able to initialize a set of flags to something; best practice is for the provider of the flags enum to provide a "None" that equals zero but not everyone does. (2) because it seems odd to have an enum field initialized automatically to zero but have no way to check to see if it is still that value without a cast. Due to various issues, we actually allow any constant zero, not just any literal zero, to convert to enum. – Eric Lippert Jan 03 '11 at 15:40
  • 6
    So fix the spec; distinguishing between `expression` and `(expression)` (or `((((expression))))`) is bad language design. – Jim Balter Apr 13 '14 at 04:07
40

There are corner cases when presence of parentheses can have effect on the program behavior:

1.

using System;

class A
{
    static void Foo(string x, Action<Action> y) { Console.WriteLine(1); }
    static void Foo(object x, Func<Func<int>, int> y) { Console.WriteLine(2); }

    static void Main()
    {
        Foo(null, x => x()); // Prints 1
        Foo(null, x => (x())); // Prints 2
    }
}

2.

using System;

class A
{
    public A Select(Func<A, A> f)
    {
        Console.WriteLine(1);
        return new A();
    }

    public A Where(Func<A, bool> f)
    {
        return new A();
    }

    static void Main()
    {
        object x;
        x = from y in new A() where true select (y); // Prints 1
        x = from y in new A() where true select y; // Prints nothing
    }
}

3.

using System;

class Program
{
    static void Main()
    {
        Bar(x => (x).Foo(), ""); // Prints 1
        Bar(x => ((x).Foo)(), ""); // Prints 2
    }

    static void Bar(Action<C<int>> x, string y) { Console.WriteLine(1); }
    static void Bar(Action<C<Action>> x, object y) { Console.WriteLine(2); }
}

static class B
{
    public static void Foo(this object x) { }
}

class C<T>
{
    public T Foo;
}

Hope you will never see this in practice.

Vladimir Reshetnikov
  • 11,750
  • 4
  • 30
  • 51
26

No, there is no difference other than syntactical.

Steven Sudit
  • 19,391
  • 1
  • 51
  • 53
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
3

A good way to answer questions like this is to use Reflector and see what IL gets generated. You can learn a lot about compiler optimizations and such by decompiling assemblies.

Bryan
  • 2,775
  • 3
  • 28
  • 40
  • 6
    That would certainly answer the question for the one specific case, but that wouldn't necessarily be representative of the entirety of the situation. – Beska Feb 02 '10 at 20:57
  • Disagree. It gives the person a direction to answer the question. – Bryan Feb 03 '15 at 14:26