Are parentheses around the result significant in a return statement?
Asked Answered
H

10

93

Is there a difference between these two statements inside a function?

bool returnValue = true;
// Code that does something
return(returnValue);

and this?

bool returnValue = true;
// Code
return returnValue;

The former has parentheses around returnValue.

Humphries answered 21/1, 2011 at 18:56 Comment(3)
Thanks Rob, you successfully captured the spirit of the question. In Essence I was wondering whether the compiler did anything special (like trying to evaluate the expression first) or if it just ignored it.Humphries
It is difficult to answer this question for any c++ / c. It would be good to be more specific on the language definition, but I do not know how to fix that 9 years later.Cloots
For C there is a duplicate #162379Cloots
C
150

As of C++14, there is a difference.

C++14 adds a fringe case where parentheses around a return value may alter the semantics. This code snippet shows two functions being declared. The only difference is parentheses around the return value.

int var1 = 42;
decltype(auto) func1() { return var1; } // return type is int, same as decltype(var1)
decltype(auto) func1() { return(var1); } // return type is int&, same as decltype((var1))

In the first func1 returns an int and in the second one func1 returns an int& . The difference in semantics is directly related to the surrounding parentheses.

The auto specifier in its latest form was introduced in C++11. In the C++ Language Spec it is described as:

Specifies that the type of the variable that is being declared will be automatically deduced from its initializer. For functions, specifies that the return type is a trailing return type or will be deduced from its return statements (since C++14)

As well C++11 introduced the decltype specifier which is described in the C++ Language Spec:

Inspects the declared type of an entity or queries the return type of an expression.

[snip]

  1. If the argument is either the unparenthesised name of an object/function, or is a member access expression (object.member or pointer->member), then the decltype specifies the declared type of the entity specified by this expression.

  2. If the argument is any other expression of type T, then

a) if the value category of expression is xvalue, then the decltype specifies T&&

b) if the value category of expression is lvalue, then the decltype specifies T&

c) otherwise, decltype specifies T

[snip]

Note that if the name of an object is parenthesised, it becomes an lvalue expression, thus decltype(arg) and decltype((arg)) are often different types.

In C++14 the ability to use decltype(auto) was allowed for function return types. The original examples are where the semantic difference with parentheses comes into play. Revisiting the original examples:

int var1 = 42;
decltype(auto) func1() { return var1; } // return type is int, same as decltype(var1)
decltype(auto) func1() { return(var1); } // return type is int&, same as decltype((var1))

decltype(auto) allows the trailing return type in the function to be deduced from the entity/expression on the return statement. In the first version return var1; is effectively the same as returning the type decltype(var1) (an int return type by rule 1 above) and in the second case return (var1); it's effectively the same as decltype((var1)) (an int & return type by rule 2b).

The parentheses make the return type int& instead of int, thus a change in semantics. Moral of the story - "Not all parentheses on a return type are created equal"

Confluence answered 2/9, 2014 at 4:42 Comment(6)
The return statement without parenthesis is still an lvalue expression, right? Unless it's being treated as an xvalue in that scenario. Can you explain the value category of the return without parenthesis?Cloistered
The return statement returns a read of the expression fed into it, i.e. it captures an rvalue from the expression it contains and returns that. We never return an lvalue. It may be possible that some compiler has a bug matching the description you give here, and for the reasons you give here, but it should never be the case that return (x); is equivalent to return &x;, nor should it be possible for it to result in a return of the value of x but with the type reference to x.Jacey
Wow, what a hideous language construct. Just totally ... opaque. Nice writeup though, thank you.Bizerte
C++ is an extremely interesting language. But these kind of hidden "features" drive me nuts sometimes...Awn
Our code is full of those unecessary parentheses. We also do use auto quite often. Do our semantics never change as long as we stay away from decltype? I am afraid of unexpected behavior when we move on to the next compiler version that incorporates the next Visual Studio.Woodworker
This answer fits even better to #50674546 where the question is more specific about the language (c++).Cloots
E
6

There is no difference.

One reason to use parenthesis would be if you wanted to evaluate an expression before returning but in your example, there would be no reason. See:

Parenthesis surrounding return values

for further discussion.

Eade answered 21/1, 2011 at 18:58 Comment(3)
Though even with a complicated expression, these parentheses still don't cause a different behavior. They just make the meaning more obvious (subjectively!) to human readers.Ophiolatry
@Karl "One reason to use parenthesis would be if you wanted to evaluate an expression before returning" Can you give an example of this?Burnham
@ChrisMiddleton No, because the claim is as nonsensical here as it was in that thread. There is no functional difference whatsoever between return m * x + c and return (m * x + c) or return ( (m * x) + c ) or etc. - and it doesn't look any better or more intuitive either, if you ask me.Possie
G
4

AFAIK, nothing is different.

In C++, expressions can have the form: expr or (expr). So, the latter is an expression with more typing. For further reading about this, refer to a grammar (look for "expression").

Gradey answered 21/1, 2011 at 18:58 Comment(1)
David, thanks for the link. I have the grammar in Stroustrup's C++ book, but (out of lazyness I guess) don't look at it that much, now that I have it bookmarked in my browser I can refer to it more often.Humphries
C
4

The parenthesis on the upper example are superfluous; they are effectively ignored.

It would be the same as something like...

int x = (5);

The parenthesis here are ignored as well.

Caramel answered 21/1, 2011 at 19:0 Comment(19)
Well, technically, they're not ignored, they just have no effect on the value of the expression.Sf
@John: effectively ignored. :)Caramel
+1 … this is the only answer that states that the parentheses are actually redundant and shows that their usage is a bit stupid.Omniscience
@KonradRudolph: redundant == (bit) stupid? A random example of superfluous parantheses shows that (syntactically) superfluous parentheses are always bad?Parma
@Parma In this particular case, yes. I didn't claim that all uses of syntactically redundant parentheses are "stupid" (at any rate, I wouldn't use that word today), and I don't know where you got that from. Just to be clear on the semantics, my comment didn't say "redundant = stupid", it said "redundant and stupid".Omniscience
@KonradRudolph: I deducted redundant == stupid because redundancy is the only argument against the parentheses in the answer and your comment. Or did I miss something?Parma
@Parma You're missing the code example in the answer, and the (unstated but implied) fact that virtually nobody writes code like this, even people who use parentheses around return values, because it's widely recognised that the parentheses in that example would in fact be extremely silly. Yes, there is a lot of unstated reliance on shared context in the answer and my comment.Omniscience
@KonradRudolph: The example in the answer is exactly the part of the answer I have a problem with. It's just an arbitrary example of superfluous parantheses where basically everyone agrees that that use is silly. But the superfluous parantheses are where the similarity to the return use case ends. And saying "the same as something like" (which is true on the technical level) also implies that the return use case is just as silly. This is like finding one example of a stupid "STOP" sign on a road trying to prove that all "STOP" signs are stupid.Parma
@Parma But the case is very closely (even if not exactly) analogous. I invite you to find the relevant difference that makes parentheses around return values OK. In both cases the parentheses are around a single lexeme without adjacent tokens that might lead to confusion.Omniscience
@KonradRudolph: return like for, if, while, or a function has something like an argument or an expression. The latter ones require you to use parantheses where return does not. An arbitrary choice of the language inventors. No? Also, if x would not be an int but of a class type: x.operator=(5) comes to mind... ;)Parma
@Parma No, not arbitrary at all. throw, sizeof, case, etc. also don't require parentheses. if, for etc. require them solely to prevent ambiguity with the following expression/block (simplest example to show this: if (x) +1; is valid C++, and would be ambiguous without parenthese; that's why all langauges that don't have parentheses around if expressions require some token afterwards to disambiguate, e.g. :, then, { etc.). Does this clear it up?Omniscience
@KonradRudolph: It's an arbitrary (purisitcal) choice to say if, while, for do not require { and } if they are followed by a single statement. And thus we need parantheses there. But the better example: A function call does not required parantheses, does it? . It's just arbitrary. It's just because mathematicians do it. Neither do function definitions or declarations.Parma
@Parma How is a function call better? It has the same syntactic limitations as if, in that f(x) + 1 is ambiguous without parentheses. Sure, it's arbitrary that we don't use e.g. Haskell syntax, and you're wrong in fact: C++ syntax does not mirror what mathematicians do, because mathematics generally does not use parentheses around the argument of function application ("f x" is conventional notation for function application in mathematics). So yes, in the end the choice is arbitrary. But it is not arbitrary that return (and throw and sizeof, etc.) is different from if etc.Omniscience
@KonradRudolph: It is not ambiguous. It's a question of precendence. Else maths text books that use the form f x would have the same problem, wouldn't they? "mathematics generally does not use parentheses around the argument of function application" is not true. I cannot recall any professor using the form f x in their lectures on the chalkboard or in scripts at my university (HfT Stuttgart, faculty of mathematics). Everyone used f(x).Parma
@Parma Math text books do have the same problem (because unfortunately conventions are not universal, which your anecdote illustrates perfectly; although I find it hard to believe that none of your professors wrote e.g. logx or sinx: parentheses, or even spaces, around the argument are very rare here; if you disbelieve me, just check what typesetting TeX produces by default). Yes, of course ambiguity can be solved: either via precedence rules, or via parentheses. And with that we've come back to the beginning.Omniscience
@Parma And to reinforce this point, a lot of mathematicians use redundant parentheses specifically to combat the ambiguity inherent in the lack of a universal convention, and to increase readability. Which is why it is entirely natural for C++ to adopt parentheses around expressions that otherwise introduce potential ambiguity. This is the case for if etc. but not for return etc.Omniscience
@KonradRudolph You're correct about sin x, log x, and the like. That was ofc used. I was caught up too much in the context of abstract function names like f(x) or g(x, y).Parma
@Parma ... why did your professors use different notation for specific functions than for other functions? This certainly isn't unheard of, but you must admit that it's inconsistent, and maybe not a great reference point for the design of a programming language ...Omniscience
@KonradRudolph: Because h x sin x is hard to read on a chalkboard, And you have to know h is a function. h(x)sin x is much clearer. But this is getting OT now.Parma
B
3

No, there are no difference in your code.

Bullheaded answered 21/1, 2011 at 18:58 Comment(0)
G
1

No difference!!

People use parenthesis if there's a complex expression involved.

BTW return is a statement not a function.

Grapher answered 21/1, 2011 at 18:57 Comment(0)
V
1

Nope there's no difference between the two, although you can include parenthesis if it makes the expression easy to read and clear.

Vow answered 21/1, 2011 at 19:19 Comment(1)
...but it never does. Why would it? What's difficult to read about an unparenthesised expression? Adding parentheses just looks like clutter to me. As for seeming clearer, do people think return is a greedy operator and that return m * x + c might return m and discard the rest, or what?Possie
W
1

You're abusively slowing down the compiler!

The presence of parenthesis not only slow down the preprocessing phase, but they generate a more complicated Abstract Syntax Tree too: more memory, more computation.


From a semantic point of view ? They are exactly identical. Whether there are parenthesis or not the return statement will fully evaluate the expression before returning it.

Waisted answered 21/1, 2011 at 19:52 Comment(6)
My thinking exactly. By making the compiler do unnecessary work parsing useless clutter it is nearing the heat death of the universe for no good reason.Vaseline
How much of a difference does that seriously make? Even over a large code base? Is that a good guideline for writing code? Making life for the compiler easier? And we're talking about hyper-micro-optimizations here, not about a huge impact in compile time that is noticeable by a human. Are curly braces used with ifs or loops bad too if those only contain one statement? Maybe we shouldn't use comments in code either. Pointless work for the compiler. Functions and variables should only have one-character names, too. Faster to process. Right?Parma
IMHO primarily the code should be easy to understand. Not optimized. Neither for compile-time nor run-time.Parma
@DrP3pp3r: This answer is obviously sarcastic. Given how many MBs of header the preprocessor pulls in, a few hundred more parentheses will be meaningless performance wise. With that said, I encourage writing for readability, and that means avoiding needless clutter -- there is no point in having parentheses around the expression passed to the return statement.Waisted
@MatthieuM.: Didn't catch the sarcasm, my bad. Parentheses around function arguments (maths functions got them, so we got them here, I guess), after ifs, fors, and while are not necessary either, still the language inventors chose to put them there). Are they clutter? Also, readability might be quite a subjective thing here. Maybe where you see clutter others see order. Maybe let's go with Alexandrescu: "Don't sweat the small stuff."Parma
@DrP3pp3r: Actually, in Rust, there's no parenthesis round in if, for, or while, and they're not missed. Parentheses around functions arguments are more difficult to get rid of: should f 3 + 4 be parsed as f(3) + 4 or f(3 + 4)? Precedence can be used, but precedence rules can quickly become confusing.Waisted
S
0

They are identical. I see the parenthesis syntax quite often, and I always ask those who use it: why? And none can answer why they use it.

To bluntly sum it up, parenthesis around returning expressions are used by people who don't quite grasp the difference between function-like macros and functions, or who are confused about the operator precedence or order of evaluation rules in C. There is no coding style benefit from using parenthesis.

Thus

return value;

is more correct than

return (value)

because the latter suggests you don't quite know what you are doing :)

Slope answered 21/1, 2011 at 21:1 Comment(5)
"Why?" Maybe for some sort of consistency. If, while, for are no functions either but parantheses are necessary there.Parma
@Parma return is a jump statement, not a selection or iteration statement. So it should be compared to goto, break and continue rather than anything else. Do you use parenthesis whenever you use goto, break or continue? If so, how did you even manage that syntax-wise?Slope
I disagree with your comparison argument. As return technically/syntactically is a jump statement, it has a similarity with functions, ifs, whiles, and fors: It takes some argument(s))/expression(s). break and continue don't. goto does, but doesn't allow parentheses. Arbitrary design choice of the language inventors? You don't need them there? Neither do you with functions, ifs, whiles, and fors. Starting with the 2nd sentence your answer becomes opinion-based IMHO.Parma
@Parma First of all, this answer is ancient, from a different time with different standards regarding what's off-topic. "Neither do you with functions, ifs, whiles, and fors." err yes, you do. Now if you wish to compare return and if, the formal syntax for return is: return expression ;. The formal syntax for if is if ( expression ). Like it or not, that's how the language was designed. if requires parenthesis by the formal syntax definition.Slope
I think you misunderstood me. Yes, ofc with the way the syntax is you need parentheses with if, for, while. But it was not necessary to define the syntax this way. There are enough languages that showcase that. It was a choice of the language creators of C to do it this way. And for return, they decided differently. Not all their choices were great. And yes, there's the technical definition and there's the human perspective. Code is for humans to read and write. You like it puristical others don't.Parma
D
-3

Both are the same in your case.

Densify answered 2/9, 2014 at 4:54 Comment(3)
M.M could you please explain your comment?Densify
if a is 5 then return a++; and return (a++); (which is the same) will both return 5Predicative
specificaly, postinc/decrement returns the pre-modification value of its operand, and no amount of parentheses or other fruitless attempts at coercion will change that.Possie

© 2022 - 2024 — McMap. All rights reserved.