Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do STL numeric algorithms use 'op' rather than 'op='?

Tags:

c++

stl

Why do std::numeric algorithms seem to prefer op instead of op=? For example, here is the implementation of std::accumulate in LLVM:

template <class _InputIterator, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
_Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
{
    for (; __first != __last; ++__first)
        __init = __init + *__first;
    return __init;
}

Would this not be potentially more efficient/less verbose/better if implemented using the += operator?

like image 472
Daniel Avatar asked Mar 04 '15 19:03

Daniel


3 Answers

It is defined like this in the standard…

The standard is defined in terms of +, not +=:

26.7.2 Accumulate [accumulate]

template <class InputIterator, class T>
  T accumulate(InputIterator first, InputIterator last, T init);
template <class InputIterator, class T, class BinaryOperation>
  T accumulate(InputIterator first, InputIterator last, T init,
               BinaryOperation binary_op);

Effects: Computes its result by initializing the accumulator acc with the initial value init and then modifies it with acc = acc + *i or acc = binary_op(acc, *i) for every iterator i in the range [first,last) in order.

Same holds for other numerical algorithms.

…and the standard is based on STL…

But that's the reason why they're implemented like this nowadays. However, to learn about the original reason, one needs to go further down the rabbit hole:

Requirements on types

For the first version, the one that takes two arguments:

  • InputIterator is a model of Input Iterator.
  • T is a model of Assignable.
  • If x is an object of type T and y is an object of InputIterator's value type, then x + y is defined.
  • The return type of x + y is convertible to T.

…and the STL has been created by…?

So, why is that? Lets ask Alexander Stepanov, the mind behind STL:

[A] user has asked a [question] on StackOverflow two days ago concerning the implementation and formulation of numerical algorithms like accumulate or inner_product, which are defined in terms of + instead of += (section 26.7 in ISO C++11).

I've tried to find some rationale behind the decision, but even the version on SGI's page doesn't mention anything regarding this particular choice of the operator.

Was the choice of the operator (a = a + b instead of a += b) only based on your personal preference, as some comments assume? Was a+b the more natural way to write the operation back then? Or was it simply a matter of symmetry between a = a +b and a = bin_op(a,b)?

-- [Zeta]

Now, before you read his answer, remember that he started to write a generic library about ~30 years ago, and his and Meng Lee's initial document The Standard Template Library will have its twenty years anniversary this October. Without further ado, I present his answer:

I suspect that it was a matter of symmetry between a = a + b and a = bin_op(a,b), but I really do not remember. I should have written a rationale document stating all the reasoning between different design choices in STL, but I did not. Sorry.

(If Stepanov reads this by any chance: thanks again for your answer!)

I personally believe that the inspiration by Common Lisp's reduce has been another factor, but that's just speculation.

What can one learn from this?

Sometimes, decision in a standard are based on personal preference and elegance. For example, if Stroustrup had written the STL, he would have "strongly prefer[ed] the use of a+=b as being a more direct expression of intent and typically faster than a=a+b". However, I have to admit that the symmetry between a = a+b and a=bin_op(a,b) has its own beauty.

That being said, this a+=b and a=a+b controversy will promote challenges:

This issue will become very important when we define standard concepts, and I do not know how it will be resolved. [Stroustrup; also thanks to him for answering my question!]

That's all, I hope you've enjoyed the ride through a little bit of C++ history.

like image 86
Zeta Avatar answered Oct 25 '22 05:10

Zeta


It might be more efficient, and would clearly be less verbose.

The usual reason for doing things this way is to minimize the requirements on the underlying type. If you used +=, then the underlying type would have to support +=. For something like int that's trivial and already present, but for a class you define, it's entirely possible would define + and =, but not the compound += (in which case, code that used += would obviously fail).

like image 21
Jerry Coffin Avatar answered Oct 25 '22 07:10

Jerry Coffin


In my opinion the main reason is that you could use standard functional object std::plus and get the same result as with operator + the same way as using operator < and standard functional object std::less in sorting algorithms like std::sort.

like image 1
Vlad from Moscow Avatar answered Oct 25 '22 07:10

Vlad from Moscow