<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<style type="text/css">
pre {margin-left:20pt; }
pre > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
pre > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
body { color: #000000; background-color: #FFFFFF; }
del { text-decoration: line-through; color: #8B0040; }
ins { text-decoration: underline; color: #005100; }

p.example { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract { margin-left: 2em; background-color: #F5F6A2;
  border: 1px solid #E1E28E; }

p.function { }
.attribute { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;
  padding-right: 1ex; }
.attribute dd { margin-left: 0em; }

blockquote.std { color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stddel { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5empadding-right: 0.5em; ; }

blockquote.stdins { text-decoration: underline;
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3; padding: 0.5em; }

table.header { border: 0px; border-spacing: 0;
  margin-left: 0px; font-style: normal; }

table { border: 1px solid black; border-spacing: 0px;
  margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;
  padding-left: 0.4em; border: none; 
  padding-right: 0.4em; border: none; }
td { text-align: left; vertical-align: top;
  padding-left: 0.4em; border: none;
  padding-right: 0.4em; border: none; }
</style>

<title>Comments on P0119: Overload sets as function arguments</title>
</head>

<body>

<table class="header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;<th> <td>P0382R0</td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;<th> <td>2016-05-29</td>
  </tr>
  <tr>
    <th>Project:&nbsp;&nbsp;<th> <td>Programming Language C++, Evolution Working Group</td>
  </tr>
  <tr>
    <th>Reply-to:&nbsp;&nbsp;<th> <td><address>Tomasz Kamiński &lt;tomaszkam at gmail dot com&gt;</address></td>
  </tr>
</tbody></table>

<h1><a name="title">Comments on P0119: Overload sets as function arguments</a></h1>

<h2><a name="intro">1. Introduction</a></h2>

<p>The aim of this paper is to present the authors comments on the impact of the change proposed in 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0119r1.pdf">P0119R1: Overload sets as function arguments</a>.
At the begin I would like to clarify that I see a great need for a language level feature that would allow programmers
to easily create an closure that wraps polymorphic calls to function with given name.</p>

<p>Observations and comments gathered in this paper are related to only one of aspect of the feature, that makes the compiler
responsible for decision in which situation the closure generation will actually be performed. As consequence all of 
them would be voided by design, that would allow programmer explicitly request the generation of the functor
object. This may be achieved, for example by using <code>[]<em>id-expression</em></code> syntax proposed in
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3617.htm">N3617: Lifting overload sets into function objects</a>
while keeping the same rules for functor generation.</p>


<!--h2><a name="toc">Table of contents</a></h2-->

<h2><a name="fragility">2. Fragility of the program semantics</a></h2>

<p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0119r1.pdf">P0119R1</a>
proposes that <code><em>id-expression</em></code> passed as argument for an unconstrained template parameter
means two different things based on whether <code><em>id-expression</em></code> refers to a unique
function or a function overload set, as seen at the point of its processing.
In other words, whether we intepret <code><em>id-expression</em></code> as a pointer-to-function or
as an implicitly declared closure depends on number and type of declarations of function
with name <code><em>id-expression</em></code> have been seen prior to its parsing.</p>

<p>This makes the meaning of the program sensitive to the order of declarations, 
and even a change as slight as the order of included headers may alter the behavior of the program.</p>

<h3><a name="fragility.example">2.1. Example program</a></h3>
<p>Let's consider the program comosed of the following files:</p>

<p><b>File: <code>container1.hpp</code></b></p>
<pre>namespace cont
{
  class C1 //container
  {
    /* ... */
  };

  bool empty(C1 const&amp;);
}</pre>

<p><b>File: <code>container2.hpp</code></b></p>
<pre>namespace cont
{
  class C2 //container
  {
    /* ... */
  };

  bool empty(C2 const&amp;);
}</pre>

<p><b>File: <code>remove_empty.hpp</code></b></p>
<pre>#include &lt;algorithm&gt;

namespace cont
{
  template&lt;typename I&gt;
  I remove_empty(I first, I last)
  { return std::remove(first, last, empty); } //P: point of checking of visible overloads of empty.
}</pre>


<p><b>File: <code>main.cpp</code></b></p>
<pre>#include &lt;vector&gt;
#include "container1.hpp"
#include "container2.hpp"
#include "remove_empty.hpp"

namespace my_cont
{
  class MC 
  {
    /* ... */
  };

  bool empty(MC const&amp;);
}

int main()
{
  std::vector&lt;cont::C1&gt; vc1(10);
  cont::remove_empty(vc1.begin(), vc1.end()); // 1

  std::vector&lt;cont::C2&gt; vc2(10);
  cont::remove_empty(vc2.begin(), vc2.end()); // 2

  std::vector&lt;my_cont::MC&gt; vmc(10);
  cont::remove_empty(vmc.begin(), vmc.end()); // 3
}</pre>

<p>In the case of the above program there will be two overloads of <code>empty</code> visible thought normal
lookup at the point of use of <code>empty</code> as template parameter (marked as <code>//P</code>).
This according to the wording presented in the paper lead to generation of the code equivalent to:</p>
<pre>
  template&lt;typename I&gt;
  I remove_empty(I first, I last)
  { return std::remove(first, last, [](auto&amp;&amp;... args) { return empty(std::forward&lt;decltype(args)&gt;(args)...); });
</pre>
<p>The closure generated in place of <code>empty</code> identifier, performs the unqualified call of the function, 
so it will consider overloads of <code>empty</code> found by ADL. As consequence both lines marked as <code>//1</code>, <code>//2</code> 
and <code>//3</code> will compile, while for the <code>//3</code> line the <code>my_cont::empty</code> declaration will be found thought ADL.</p>

<p>However if the order of the includes in the <code>main.cpp</code> will be changed to:</p>
<pre>#include "container1.hpp"
#include "remove_empty.hpp"
#include "container2.hpp"</pre>
<p>At the point of <code>//P</code> only one declaration one of <code>empty</code> will be visible, so according
to the wording paper, this will lead to generation of following code.</p>
<pre>
  template&lt;typename I&gt;
  I remove_empty(I first, I last)
  { return std::remove(first, last, &amp;empty); }
  //As the empty is not-overloaded, the <code>&amp;empty</code> is unambiguous
  //and produces <code>bool (*)(cont::C1 const&amp;)</code> 
</pre>
<p>This resolution is selected to preserve current compatibility that resolves <code>function-id</code>
   pointing to single not overloaded function, to function pointer. That means that the lines <code>//1</code>
   and <code>//3</code> will not longer compile as both <code>cont::C2</code> and <code>my_cont::MC</code>
   will not be accepted as argument for <code>bool (*)(cont::C1 const&amp;)</code>.

<p>For similar reasons only line <code>//2</code> will compile, if the header will be placed in following order:</p>
<pre>#include "container2.hpp"
#include "remove_empty.hpp"
#include "container1.hpp"</pre>

<p>Finally the program will produce error mentioning not unresolved name <code>empty</code>,
   if the header will be ordered as follows:</p> 
<pre>
#include "remove_empty.hpp"
#include "container1.hpp"
#include "container2.hpp"</pre>

<h3><a name="fragility.odr">2.2. ODR Violation</a></h3>

<p>The above example showed how the semantics of the same instantiation of the 
<code>filter_empty</code> changes depending of the order of the headers in the program.
In addition their expose a deeper problem with proposed resolution: depending on the
order of the header included in the transaction units, the semantic of the
same instantiation of <code>filter_empty</code> will change, which according
to the standard (14.6.4.1 [temp.point] p8) leads to the ill-formed programs.</p>

<h3><a name="fragility.summary">2.3. Summary</a></h3>

<p>As the above example shows up, the use of the feature of passing overloaded functions sets
as template arguments inside of function template lead to fragile code that changes it meaning
and validity depending on the subtle changes in the order of declarations (headers). This is 
caused by the fact that generation of closure depends only on normal lookup and ignores ADL and
two phase lookup, that were created to avoid such problems in generic code in first place.</p>

<h2><a name="usability">3. Scope and usability</a></h2>

<p>The aim <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0119r1.pdf">P0119R1</a>
is to make following code to be well formed when multiple overloads of function <code>f</code> are
found:</p>
<pre>template&lt;typename  I&gt;
void apply_f(I first, I last)
{
  transform(first, last, f);
}</pre>

<p>Although the author believes that we should we aim to provide more generic extension that will allow
us to transform any function name to an closure.</p>

<h3><a name="usability.adl">3.1. Argument Depended Lookup</a></h3>

<p>Let consider following function example:</p>
<pre>template&lt;typename  I&gt;
I remove_empty(I first, I last)
{ return std::remove_if(first, last, [](auto const&amp; arg) { return empty(arg): }); }</pre>

<p>I think that it would be reasonable to expect that invocation of above function (and
function itself) can be replaced by the <code>std::remove_if(first, last, empty)</code> 
without any loss of efficiency and readability.</p>

<p>To make the call <code>std::remove_if(first, last, empty)</code>  equivalent
to <code>remove_empty(first, last, empty)</code> we need to make sure that closure 
will be generated in place of <code>empty</code>. According to rules proposed in
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0119r1.pdf">P0119R1</a>
this will only take place if declaration(s) of <code>empty</code> found
thought normal lookup will represent overload set (multiple overloads or function template).

But it is possible that at the point of declaration of <code>remove_empty</code> function, 
even no declaration of <code>empty</code> may be visible, as the unqualified call to 
<code>empty(arg)</code> allow overloads to be found by ADL at point of <code>remove_empty</code>
instantiation.</p>

<h3><a name="usability.default-arguments">3.2. Default arguments</a></h3>

<p>In addition to usual means, like declaration of multiple overloads of single function name or 
declaring it as function template, there is one additional way to create a function that can be
called with more than one set of arguments. We can declare single function with default parameter:</p>
<pre>
void increment(int&amp; i, int n = 1)
{ i += 1; }
</pre>

<p>Lets imagine that our goal is to produce a <code>increment_all</code> function that will increment
by all elements in given range of integers. We could implement it using the <code>std::for_each</code>
with <code>increment</code> passed as argument. 

Implementation using proposed feature may look like:</p>
<pre>template&lt;typename I&gt;
void increment_all(I first, I last)
{
  std::for_each(first, last, increment);
}</pre>

<p>At the first glance, we could expect that in place of functor argument the following
closure will be generated 
<code>[](auto&amp;&amp;... args) { return increment(std::forward&lt;decltype(args)&gt;(args)...); }</code>
and it will be invoked with only one <code>int&amp; i</code> argument. 
However this will not be the case, because case only one declaration of <code>increment</code>
function is visible at the point of <code>increment_all</code> and this identifier will be
resolved to <code>void(*)(int&amp;, int)</code> function pointer.</p>

<h3><a name="usability.indirect-call">3.3. Avoiding indirection through function pointers</a></h3>

<p>Even in situation when the <code>std::find_if(first, last, func)</code> compiles correctly
today, function pointer is be passed to the invoked algorithm and indirect call is be performed
for each element of the collection. As this may negatively affect performance, the user
may want to pass functor object instead.</p>

<p>Despite its usefulness, such transformation change cannot be performed unconditionally, 
as existing code may depend on additional semantic that is provided by the function pointers 
when compared to closure object: nullability and assignability from pointer to function with
same signature.</p>

<h2><a name="acknowledgements">4. Acknowledgements</a></h2>

<p>I would like to thank Philipp Juschka for originally proposing the idea of lifting expression
   and Andrew Sutton for continuing work on this features.</p>

<p>Andrzej Krzemieński offered many useful suggestions and corrections to the proposal.</p>

<p>Special thanks and recognition goes to Sabre (<a href="http://www.sabre.com/">http://www.sabre.com</a>) 
   for supporting the production of this proposal, and for sponsoring author's trip to the Oulu for WG21 meeting.</p>

<h2><a name="literature">5. References</a></h2>

<ol>
  <li>Andrew Sutton, 
      "Overload sets as function arguments" 
      (P0119R1, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0119r1.pdf">
                http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0119r1.pdf</a>)</li>

  <li>Philipp Juschka, 
      "Lifting overload sets into function objects" 
      (N3617, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3617.htm">
              http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3617.htm</a>)</li>
</ol>

</body></html>
