<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0065)http://home.twcny.rr.com/hinnant/for_mike/Issue_225_and_swap.html -->
<!--This file created 3/16/01 5:23 PM by Claris Home Page version 2.0--><HTML><HEAD><TITLE>Issue 225 and swap</TITLE>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type>
<META content="MSHTML 5.00.2919.6307" name=GENERATOR><X-SAS-WINDOW RIGHT="534" 
LEFT="4" BOTTOM="757" TOP="42"></HEAD>
<BODY bgColor=#ffffff>
<P align=right>
<TABLE border=0>
  <TBODY>
  <TR>
    <TD width=125>
      <P align=right>Document number: </P></TD>
    <TD width=190>
      <P>J16/01-0003 = WG21 N1289 </P></TD></TR>
  <TR>
    <TD width=125>
      <P align=right>Date: </P></TD>
    <TD width=190>
      <P>March 15, 2001 </P></TD></TR>
  <TR>
    <TD width=125>
      <P align=right>Author: </P></TD>
    <TD width=190>
      <P>Howard Hinnant, Metrowerks </P></TD></TR>
  <TR>
    <TD width=125>
      <P></P></TD>
    <TD width=190>
      <P><A href="mailto:hinnant@metrowerks.com">hinnant@metrowerks.com</A> 
    </P></TD></TR></TBODY></TABLE></P>
<H2>
<CENTER>Comments on Lib Issues 225 and 229</CENTER></H2>
<H3>
<CENTER>Introduction</CENTER></H3>
<P>This document concerns lib issue 225 and the proposed resolution: </P>
<BLOCKQUOTE>
  <P>Unless otherwise specified, no global or non-member function in the 
  standard library shall use a function from another namespace which is found 
  through argument-dependent name lookup (3.4.2 
[basic.lookup.koenig]).</P></BLOCKQUOTE>
<P>Although I generally agree with the resolution, the basic intent of this 
document is to clearly outline where and why "Unless otherwise specified" should 
appear. This document also applies to lib issue 229 (which is very closely 
related).</P>
<P>The bulk of this document concerns only one method: swap. But there are a few 
other methods involved as well. To begin, I would like to define the term 
<B>swappable</B> so that I may easily refer to this definition later in the 
paper.</P>
<H3>
<CENTER>Swappable Concept</CENTER></H3>
<P>This concept is modeled after similar concepts in the standard. Namely:</P>
<UL>
  <LI>20.1.1 - Equality comparison 
  <LI>20.1.2 - Less than comparison 
  <LI>20.1.3 - Copy construction 
  <LI>23.1/4 - Assignable requirements </LI></UL>
<P><B>swappable</B> requirements:</P>
<P>In the table t and u are non-const values of a type T.</P>
<P>
<CENTER><B>swappable</B> requirements
<TABLE border=1>
  <TBODY>
  <TR>
    <TD width=64>
      <P>expression </P></TD>
    <TD width=71>
      <P>return type </P></TD>
    <TD width=181>
      <P>post-condition </P></TD></TR>
  <TR>
    <TD width=64>
      <P>swap(t, u) </P></TD>
    <TD width=71>
      <P>void </P></TD>
    <TD width=181>
      <P>t has the value originally held by u, and u has the value originally 
      held by t </P></TD></TR></TBODY></TABLE></CENTER>
<P></P>
<P>For a type T, being <B>swappable</B> does not require (or imply) 
<B>copyconstructible</B> nor <B>assignable</B>. But if a type is both 
<B>copyconstructible</B> and <B>assignable</B>, then it is also 
<B>swappable</B>. For example:</P>
<BLOCKQUOTE><PRE>class Swappable
{
public:
	Swappable(int size) : size_(size), data_(new int[size]) {}
	~Swappable() {delete [] data_;}
	friend void swap(Swappable&amp; x, Swappable&amp; y);
private:
	int size_;
	int* data_;
&nbsp;
	Swappable(const Swappable&amp;);             // not defined
	Swappable&amp; operator=(const Swappable&amp;);  // not defined
};
&nbsp;
void
swap(Swappable&amp; x, Swappable&amp; y)
{
	std::swap(x.size_, y.size_);
	std::swap(x.data_, y.data_);
}</PRE></BLOCKQUOTE>
<P><TT>Swappable</TT> is <B>swappable</B>, but not <B>copyconstructible</B> nor 
<B>assignable</B>.</P>
<P>Non-const scalars such as <TT>int</TT> and <TT>int*</TT> are <B>swappable</B> 
because they are <B>copyconstructible</B> and <B>assignable</B>. They can be 
swapped with std::swap.</P>
<H3>
<CENTER>swap is just another primitive</CENTER></H3>
<P>A typical client-level class may have one or several methods, both at class 
scope and at namespace scope that are used by the standard library. Indeed, most 
(but not all) of these methods are neatly written up in various "requirements" 
sections in the standard. Examples include default constructible, copy 
constructible and assignable. These three requirements refer to member methods 
of an object.</P>
<P>The equality and less-than comparison requirements can refer to methods 
either at class scope, or at namespace scope. Although not specifically 
mentioned, the equality and less-than comparison requirements appear to require 
that if the method is defined at namespace scope, then it must be in the same 
namespace as the class definition. There are two reasons for this implied 
requirement:</P>
<OL>
  <LI>17.4.3.1/1 generally forbids adding declarations or definitions to 
  namespace std except for template specializations of a standard library 
  template. 
  <LI>These methods are called as unqualified names from within the std::lib. 
  The only namespaces that will be searched are std, and whatever namespace is 
  associated with the client's class. </LI></OL>
<P>This implied requirement does not come as a surprise to the general C++ 
programmer. Indeed, it is considered good programming practice to group 
namespace scope functions of a class within the same namespace as the class, 
whether or not the std::lib is involved (<A 
href="http://www.gotw.ca/publications/xc++.htm">Items 31-34, Exceptional C++, 
Herb Sutter</A>).</P>
<P>Another example of primitive requirements in the standard is in sections 
24.5.1 and 24.5.2. These are the istream_iterator and ostream_iterator sections. 
The standard says that these use operator &gt;&gt; and operator &lt;&lt; 
respectively. No mention is made of namespaces. Nor is there a reference to 
"readable" or "writeable" requirements. Here it is implied that an unqualified 
call to operator&gt;&gt;(std::istream&amp;, your_object&amp;) will be made. You 
had better set up your operator&gt;&gt; so that it will work! (i.e. put it in 
the same namespace as your class).</P>
<P>Had Jerry chosen read(istream&amp;, MyClass&amp;) instead of 
operator&gt;&gt;, would we today be questioning what namespace "read" was 
supposed to go in? I'm grateful to Jerry that this is not an issue we have to 
wrestle with. Since "read" was implemented as an operator, we currently accept 
without question that koenig lookup should find the correct method in the 
namespace of MyClass.</P>
<P>I believe swap is a primitive. More a part of a class's intrinsic interface, 
than a std::lib method. Similar to:</P>
<BLOCKQUOTE><PRE>istream&amp; operator &gt;&gt;(istream&amp;, MyClass&amp;);
ostream&amp; operator &lt;&lt;(ostream&amp;, const MyClass&amp;);
bool operator ==(const MyClass&amp;, const MyClass&amp;);
bool operator &lt;(const MyClass&amp;, const MyClass&amp;);
MyClass operator +(const MyClass&amp;, const MyClass&amp;);</PRE></BLOCKQUOTE>
<P>Indeed, if C/C++ had a built-in operator that meant swap, I don't believe we 
would be having this conversation.</P>
<H3>
<CENTER>What's a primitive?</CENTER></H3>
<P>So I think swap is a primitive. What else do I think is a primitive? Where do 
we draw the line? Are we expecting another visit from Pandora so soon?</P>
<P>I'm afraid I don't have a good definition of primitive. My dictionary defines 
primitive (in part) as:</P>
<BLOCKQUOTE>
  <P><B>primitive</B> <I>adj</I> not derived, original, primary, assumed as a 
  basis, ...</P></BLOCKQUOTE>
<P>This is a concept not unlike pornography. I have difficulty with a precise 
definition, but I know it when I see it. Perhaps other members of the committee 
can help me with this. In short, a primitive is something that has more to do 
with a type, than it has to do with an algorithm in the std::lib. Perhaps 
primitive is not the right adjective to be describing this concept.</P>
<H3>
<CENTER>So how many primitives are there?!</CENTER></H3>
<P>The bad news is: more than one.</P>
<P>The good news is: not that many.</P>
<P>For the moment I would like to define anything implemented as an operator 
(either built-in or overloaded) as a primitive. It would be very convenient if 
we could just stop there: methods implemented as operators are primitive and 
belong in the client's namespace, and methods not implemented as operators are 
not primitive and belong in namespace std. But I believe that this rough cut 
based on syntax and history alone is not in the best interest of the C++ 
community.</P>
<P>In addition to those methods implemented as operators, I propose the 
following list of primitives. Note that only one of them (swap) is outside of 
Section 26 (Numerics):</P>
<UL>
  <LI>swap 
  <LI>abs 
  <LI>acos 
  <LI>asin 
  <LI>atan 
  <LI>atan2 
  <LI>cos 
  <LI>cosh 
  <LI>exp 
  <LI>log 
  <LI>log10 
  <LI>pow 
  <LI>sin 
  <LI>sinh 
  <LI>sqrt 
  <LI>tan 
  <LI>tanh </LI></UL>
<P>And I think the following identifiers should be reserved as possible future 
primitives:</P>
<UL>
  <LI>acosh 
  <LI>asinh 
  <LI>atanh </LI></UL>
<H3>
<CENTER>What parts of the std::lib uses these primitives? </CENTER></H3>
<P>swap is used a fair amount in &lt;algorithm&gt;. This should really come as 
no surprise. After all, it is a primitive! :-) There are actually two 
distinctions I would like to make though. There are currently several methods 
that specifically mention swap, either in their effects clause, or in their 
complexity clause. In my opinion, these must call swap (not std::swap, nor a 
series of assignments). In addition there are several methods that commonly call 
swap as part of their implementation, but no mention is made of this possibility 
in the standard. I would like to allow for this possibility with "may call 
swap". That is, it is implementation defined if such a method calls std::swap, 
swap, or neither.</P>
<P>
<HR>
Must call swap
<P></P>
<BLOCKQUOTE><PRE>iter_swap (1)
swap_ranges
reverse
random_shuffle
partition
next_permutation
prev_permutation</PRE>
  <P>These methods are currently missing any requirements statement except that 
  their use of forward or better iterator implies that the value_type is 
  assignable. Since the (proposed) implementation must call swap, the minimum 
  needed requirement on the value_type is that it is swappable.</P>
  <P>Footnote (1): Implementations are allowed to specialize iter_swap. If such 
  specializations do not call swap, they are forbidden from assuming copy 
  constructibility or assignability of the iterator's value_type, despite the 
  container's requirements.</P></BLOCKQUOTE>
<P>
<HR>
May call swap
<P></P>
<BLOCKQUOTE><PRE>rotate
pop_heap
sort_heap
sort
partial_sort
partial_sort_copy
nth_element</PRE>
  <P>These methods are currently missing any requirements statement except that 
  their use of forward or better iterator implies that the value_type is 
  assignable. Since the (proposed) implementation may call swap, then the 
  value_type must be both swappable and assignable. </P></BLOCKQUOTE>
<P>
<HR>
May call swap
<P></P>
<BLOCKQUOTE><PRE>stable_partition
inplace_merge
stable_sort</PRE>
  <P>These methods are currently missing any requirements statement except that 
  their use of forward or better iterator implies that the value_type is 
  assignable. The description of these methods includes the possibility of using 
  a temporary buffer. This implies that the value_type is also copy 
  constructible. Thus swappable is already implied, clearing the way for the 
  possibility that these methods may call swap.</P></BLOCKQUOTE>
<P>
<HR>

<P></P>
<P>The rest of the proposed primitives are called by member methods of the same 
name within the valarray template (26.3.3.3).</P>
<H3>
<CENTER>Consequences</CENTER></H3>
<P>So how big of a change is this? What does it mean to implementors? And more 
importantly, what does it mean to clients of the std::lib? </P>
<P>I believe that in terms of effected code, this is a minuscule change. From a 
practical standpoint I do not think a single line of non-std::lib code will be 
broken. Up until very recently (mid 2000?), all std::lib implementations made 
most or all calls to other std::methods with the unqualified syntax. Issue 225 
is mandating that this is incorrect and several (two?) vendors have already 
modified their libs accordingly. Thus I see little or no possibility that any 
client code exists which would be surprised by a std::lib calling a swap method 
in their own namespace. Indeed, I'm sure there is much more code that would be 
surprised by this not happening.</P>
<P>The change to std::lib vendors who have not yet swept through their libs and 
qualified internal calls is significant but not overwhelming. I converted the 
Metrowerks std::lib to qualified calls in about 8 hours. For those vendors who 
have already done this job, they would have to undo qualification on swap and 
the rest of the primitives defined herein. I estimate that job to take less than 
an hour.</P>
<P>Acceptance of this proposal will undercut much (all?) of the motivation for 
relaxing 17.4.3.1/1 to allow client code to put definitions into namespace 
std.</P>
<P>I believe that this is the path that will produce the least surprise to C++ 
programmers, and at the same time, provide them with the highest quality 
tools.</P>
<P>Respectfully,</P>
<P>Howard Hinnant</P>
<ADDRESS>Senior Library and Performance Engineer</ADDRESS>
<ADDRESS>Metrowerks</ADDRESS>
<ADDRESS><A href="mailto:hinnant@metrowerks.com">hinnant@metrowerks.com</A> 
</ADDRESS></BODY></HTML>
