Small Issues on Convention

T

Tomás

Let's say we have a function that returns the result of subtracting seven
from a given number. Would you write it as:

(A)

int SubtractSeven( int const x )
{
return x - 7;
}

(B)

int SubtractSeven( int x )
{
return x -= 7;
}

(C)

int SubtractSeven( int const& x )
{
return x - 7;
}


If we just wanted to "accomplish the task", without contemplating how fast
the code will run, or how much memory it will need, then I think the natural
choice is A. Do you agree with me?

If we consider efficiency, then we may think, "Why create that temporary? We
should just re-use the parameter variable.". This would make us lean toward
B.

Considering efficiency again, we may think to ourselves, "Why even create
that parameter variable? Let's just use the one we're supplied with (if
possible)". This would have some rationale to it (I'm open to correction
here) if we were dealing with an inline function... but if we're dealing
with an outline function, then we'd be playing around with pointers under
the hood, which, in the end, will be far less efficient than our original
example.

So... my aim is to draw up some conventions for the use of A, B and C.

Firstly, when do I use method C?

1: When I want to alter the supplied variable.

2: When I'm dealing with a user-defined type which consumes quite more
memory than an "int", or if the invokation of copy constructors would
involve considerable processing and dynamic allocation of memory.

Examples:

1:
void SubtractSevenFromGivenVariable(int &x)
{
x -= 7;
}

2:
unsigned CountAmountOfVowels( std::string const & str )
{
unsigned val;

//do stuff

return val;
}


Do you agree with me on when to use C?


If we had a small POD like the following:

struct XYCoord
{
unsigned x;
unsigned y;
};

then I would be probably not pass it by reference, and just pass it by
value. Do you agree with me here?

As for A and B... which shall it be?

I think that A is more natural, and is "the way things were supposed to be",
but I don't think we can deny the efficient reuse of a variable which we see
in B.
At the moment, I use the B method, although I'd be open to
advice/suggestions.

Do we have a const parameter and return a temporary? Or do we have a non-
const parameter, and return the result of subtracting seven from it?

-Tomás
 
B

Ben Pope

Tomás said:
Let's say we have a function that returns the result of subtracting seven
from a given number. Would you write it as:

(A)

int SubtractSeven( int const x )
{
return x - 7;
}

Why pass by const when passing by value?
(B)

int SubtractSeven( int x )
{
return x -= 7;
}

The passed parameter will not be modified.
(C)

int SubtractSeven( int const& x )
{
return x - 7;
}

The passed parameter will not be modified.
If we just wanted to "accomplish the task", without contemplating how fast
the code will run, or how much memory it will need, then I think the natural
choice is A. Do you agree with me?

No. The natural choice is:

int SubstractSeven(int x) {
return x - 7;
}
If we consider efficiency, then we may think, "Why create that temporary? We
should just re-use the parameter variable.". This would make us lean toward
B.

Nope without optimisation, b probably copies x at the call site, and in
the function and on the assignment after the call.
Considering efficiency again, we may think to ourselves, "Why even create
that parameter variable? Let's just use the one we're supplied with (if
possible)". This would have some rationale to it (I'm open to correction
here) if we were dealing with an inline function... but if we're dealing
with an outline function, then we'd be playing around with pointers under
the hood, which, in the end, will be far less efficient than our original
example.

What makes you think you'd be playing around with pointers under the hood?
So... my aim is to draw up some conventions for the use of A, B and C.

Firstly, when do I use method C?

1: When I want to alter the supplied variable.

But you don't, for a start it's const, and secondly you make a copy!
2: When I'm dealing with a user-defined type which consumes quite more
memory than an "int", or if the invokation of copy constructors would
involve considerable processing and dynamic allocation of memory.

Sorry, it's copied to modify it and return it anyway. But yes, pass by
const ref when it's not a native type and you don't need to modify it.
Examples:

1:
void SubtractSevenFromGivenVariable(int &x)
{
x -= 7;
}

2:
unsigned CountAmountOfVowels( std::string const & str )
{
unsigned val;

//do stuff

return val;
}


Do you agree with me on when to use C?

See above.
If we had a small POD like the following:

struct XYCoord
{
unsigned x;
unsigned y;
};

then I would be probably not pass it by reference, and just pass it by
value. Do you agree with me here?

I'd pass it by const ref, easier to optimise, and less maintenance
hassle if XYCoord becomes "more clever".
As for A and B... which shall it be?

Neither. See above.
I think that A is more natural, and is "the way things were supposed to be",
but I don't think we can deny the efficient reuse of a variable which we see
in B.
At the moment, I use the B method, although I'd be open to
advice/suggestions.

Do we have a const parameter and return a temporary? Or do we have a non-
const parameter, and return the result of subtracting seven from it?

For built in types you are not going to modify do this:
T builtIn(T t) { return t; }

For non built in types do this:
T notBuiltin(const T& t) { return t; }

If you want to modify the parameter do this:

T& modify(T& t) { return t; }

Don't concern yourself with whether a temporary can be reused, the
compiler will do all that for you.

Personally I would expect all 3 of your functions to end up the same
with only mild optimisation.

Ben Pope
 
D

Dervish

A: int SubtractSeven( int const x )
B: int SubtractSeven( int x )
C: int SubtractSeven( int const& x )

Problem with A is, that A & B has exactly the same signature from
compiler point of view. If two things are the same usually it is better
to use only one. And usually B is used. A is a little bit too puristic.

Speaking about C, I think it should be total taboo even mention about
possibility to pass built in types by const reference or pointer to
const.
 
T

Tomás

Why pass by const when passing by value?


I have a habit whereby I stick "const" everywhere that I can. Everywhere.

Everywhere.

It may or may not lead to optimisation by the compiler -- but it shall
certainly not have a detrimental effect.

The passed parameter will not be modified.


Correct. This is as intended.

The passed parameter will not be modified.


Correct. This is as intended.
No. The natural choice is:

int SubstractSeven(int x) {
return x - 7;
}


For you, yes. My own natural choice was to stick in "const".

What makes you think you'd be playing around with pointers under the
hood?

If the function is outline, then the machine code will work with pointers to
access the memory.

Please don't enter into a discussion which goes down the road of "A compiler
is free to implement features in whichever way it please, and doesn't have
to use pointers...".

But you don't, for a start it's const, and secondly you make a copy!

I was simply showing an alternative. I realise that I don't alter its value.

For built in types you are not going to modify do this:
T builtIn(T t) { return t; }

For non built in types do this:
T notBuiltin(const T& t) { return t; }

If you want to modify the parameter do this:

T& modify(T& t) { return t; }


Yes, but...

If we want to pass by value, thus not altering the variables value, we have
a choice of either:


(T is an intrinisc type:)

T SubtractSeven(T t) { return t -= 7; }

T SubtractSeven(T t) { return t - 7; }

Abiding by my "put const wherever I can rule", then the latter would be:

T SubtractSeven(T const t) { return t - 7; }


So when we're dealing with intrinsic types, do we go with:

(A) T SubtractSeven(T const t) { return t - 7; }
-or-
(B) T SubtractSeven(T t) { return t -= 7; }


-Tomás
 
L

LuB

A: int SubtractSeven( int const x )
B: int SubtractSeven( int x )
C: int SubtractSeven( int const& x )

Keep in mind that 'x' here is passed by value in A and B. Therefore,
they are semantically the same functions. It is impossible for A or B
to alter the original x parameter. The 'const' notation becomes
irrelevant. I'd actually consider it 'confusing' since it is well known
that x is passed by value. The next person to look at this code might
wonder what you were trying to accomplish ... maybe you left off '&' or
something ...

In addition, unless you are using an environment where sizeof(&int) !=
sizeof(int) .. I don't think you gain a performance edge by using C
since, passing and int by value or reference moves the same number of
bits ...

Hth,

-LutherB
 
B

Ben Pope

Tomás said:
I have a habit whereby I stick "const" everywhere that I can. Everywhere.

Everywhere.

It may or may not lead to optimisation by the compiler -- but it shall
certainly not have a detrimental effect.

Not to the generated code, but readability may affected (one way or
another). Personally I would start to wonder why you had made it const
when it couldn't possibly be modified since it's passed by value. Then
I would wonder if you had intended it to be passed by reference.
For you, yes. My own natural choice was to stick in "const".

Then that's ok, but it doesn't actually gain you anything.
If the function is outline, then the machine code will work with pointers to
access the memory.

It would likely access it indirectly, yes. But the compiler could
inline the function, and it may optimise away the use of any indirect
access. That was my point.
Please don't enter into a discussion which goes down the road of "A compiler
is free to implement features in whichever way it please, and doesn't have
to use pointers...".

I prefer "indirection", since the use of pointers implies that it will
actually add pointers to your source before compiling it.
I was simply showing an alternative. I realise that I don't alter its value.

That did confuse me a little in combination with your functions above (I
didn't understand the use of const).
Yes, but...

If we want to pass by value, thus not altering the variables value, we have
a choice of either:


(T is an intrinisc type:)

T SubtractSeven(T t) { return t -= 7; }

The function body looks weird (to me).
T SubtractSeven(T t) { return t - 7; }

All looks normal (to me).
Abiding by my "put const wherever I can rule", then the latter would be:

T SubtractSeven(T const t) { return t - 7; }

The function prototype looks weird (to me).
So when we're dealing with intrinsic types, do we go with:

(A) T SubtractSeven(T const t) { return t - 7; }
-or-
(B) T SubtractSeven(T t) { return t -= 7; }

You know I'm going to suggest a C!

Have fun :)

Ben Pope
 
L

LuB

LuB said:
A: int SubtractSeven( int const x )
B: int SubtractSeven( int x )
C: int SubtractSeven( int const& x )

Keep in mind that 'x' here is passed by value in A and B. Therefore,
they are semantically the same functions. It is impossible for A or B
to alter the original x parameter. The 'const' notation becomes
irrelevant. I'd actually consider it 'confusing' since it is well known
that x is passed by value. The next person to look at this code might
wonder what you were trying to accomplish ... maybe you left off '&' or
something ...

In addition, unless you are using an environment where sizeof(&int) !=
sizeof(int) .. I don't think you gain a performance edge by using C
since, passing and int by value or reference moves the same number of
bits ...

Hth,

-LutherB

Oops. My apologies for the previous top post.
 
B

Ben Pope

LuB said:
In addition, unless you are using an environment where sizeof(&int) !=
sizeof(int) .. I don't think you gain a performance edge by using C
since, passing and int by value or reference moves the same number of
bits ...

....followed by zero, one or more indirections, iff the "pointer" is not
optimised away.

Ben Pope
 
R

red floyd

Not to the generated code, but readability may affected (one way or
another). Personally I would start to wonder why you had made it const
when it couldn't possibly be modified since it's passed by value. Then
I would wonder if you had intended it to be passed by reference.

How about it we want it so that x is const within SubtractSeven. Yes,
externally, they have the same effect, but it provides additional safety
inside of SubtractSeven.
 
R

Richard Herring

A: int SubtractSeven( int const x )
B: int SubtractSeven( int x )
C: int SubtractSeven( int const& x )

Problem with A is, that A & B has exactly the same signature from
compiler point of view. If two things are the same usually it is better
to use only one. And usually B is used. A is a little bit too puristic.

Speaking about C, I think it should be total taboo even mention about
possibility to pass built in types by const reference or pointer to
const.

Why? That would mean you have to make special cases for template code
which could otherwise be written identically for all argument types.
 
G

Gavin Deane

red said:
How about it we want it so that x is const within SubtractSeven. Yes,
externally, they have the same effect, but it provides additional safety
inside of SubtractSeven.

A couple of Herb Sutter's GOTW articles suggests that this isn't
helpful, although one is fairly thin on rationale.

http://www.gotw.ca/gotw/006.htm
http://www.gotw.ca/gotw/081.htm

I don't use const in this way - not so much because I have found it
detrimental, but really because I have not felt worse off for its
absence, and nobody else does it like that. Perhaps there's a certain
amount of exposing an implementation detail - this function does not
change it's copy of the parameter value - which is of no consequence to
the caller, which grates slightly with me. But the main reason I don't
do it is the reason for several of my C++ style choices: it's not the
commonly recognised idiom. And going against the principle of least
surprise for no real benefit is something I certainly want to avoid.

Gavin Denae
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,153
Latest member
NamKaufman
Top