<!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=US-ASCII">
<title>Unified Function Syntax</title>
</head>
<body>
<h1>Unified Function Syntax</h1>

<p>
ISO/IEC JTC1 SC22 WG21 N2763 = 08-0273 - 2008-09-19
</p>

<p>
Lawrence Crowl, crowl@google.com, Lawrence@Crowl.org
<br>
Alisdair Meredith, alisdair.meredith@codegear.com
</p>

<p>
This paper is a revision of N2582 = 08-0092
and reflects the consensus of the "other" library subgroup
on 15 September 2008.
The revision removes the handling of the nested declarator issue,
as core language issue 681 addresses the problem.
The revision removes the introduction of named lambdas
and block-local function definitions.
The intent is that these features be added in a later standard.
</p>

<h2>Introduction</h2>

<p>
The sytax for both
the new function declarator syntax
(<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2541.html">N2541
New Function Declarator Syntax Wording</a>)
and lambda expressions
(<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2550.pdf">N2550
Lambda Expressions and Closures:
Wording for Monomorphic Lambdas (Revision 4)</a>)
are similar.
As suggested by Alisdair Meredith
(<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2511.html">N2511
Named Lambdas and Local Functions</a>),
the syntax for both could be made more similar,
thus simplifying the view of the programmer.
The British position
(<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2510.pdf">N2510
BSI Position on Lambda Functions</a>)
supports this work.
</p>

<p>
Such a unification would address the concerns of Daveed Vandevoorde
(<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2007/n2337.pdf">N2337
The Syntax of auto Declarations</a>)
that the <code>auto</code> was too overloaded
in its use for both a new function declarator syntax
and for automatically deducing variable type
(<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1984.pdf">N1984
Deducing the type of variable from its initializer expression (revision 4)</a>).
</p>

<p>
This paper explores the syntactic unification
of function declarations and lambda expressions.
It takes the new lambda syntax
(<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2550.pdf">N2550</a>)
as the starting point for syntactic unifications,
and specific syntactic suggestions in
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2511.html">N2511</a>
no longer apply.
As a simplistic unification
would introduce unfortunate irregularities in semantics,
we also explore regularizing the semantics of such declarations.
</p>

<h2>Syntactic Unification</h2>

<p>
Our general approach is to replace the use of <code>auto</code> in
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2541.html">N2541</a>
with a <var>lambda-introducer</var> of the form <code>[]</code>.
</p>
<blockquote><pre><code>
int x=0, y=0;
[]f(int z)-&gt;int {
    return x+y+z;
}
struct s {
    int k;
    []g(int z)-&gt;int;
};
[]s::g(int z)-&gt;int {
    return k+x+z;
}
</code></pre></blockquote>

<p>
As lambda expressions can implicitly deduce the return type in simple cases,
a reasonable extension to the unified syntax
might allow the same for inline function definitions.
However, the Evolution Working Group
looked at a similar extension in some detail earlier in the process
and rejected it for the coming C++0x revision.
We see no reason to reverse that decision at this late stage.
So, the return type is required.
</p>

<p>
Finally, for more declarative consistency,
the parameter list is required, even if empty,
for function declarations.
(We do not propose to add that requirement to lambda expressions.)
</p>

<h2>Future Semantic Regularization</h2>

<p>
The intent of unified function syntax
is to enable future language features
as compatible extensions.
We discuss those extensions here,
but stress that the proposed wording does not
introduce named lambdas or nested functions.
</p>

<p>
For functions at namespace,
the <var>lambda-introducer</var> of the form <code>[]</code>
is semantically correct.
</p>

<p>
For functions at class scope,
the <var>lambda-introducer</var> of the form <code>[]</code>
is semantically correct,
with the understanding that class-scope non-static functions
still have an implicit <code>this</code> parameter.
(A more explicit <var>lambda-introducer</var> form
would be <code>[this]</code>,
but we little advantage in requiring extra syntax
were none was required before.)
</p>

<p>
For functions at block scope,
an <var>lambda-introducer</var> of the form <code>[]</code>
indicates a local function
<em>without</em> access to the containing function's local variables.
An <var>lambda-introducer</var> of any other form indicates a named lambda.
</p>
<blockquote><pre><code>
int h(int b) {
    []m(int z)-&gt;int // local function
        { return x+z; } // b is not in scope
    [&amp;]n(int z)-&gt;int // named lambda
        { return b+x+z; } // b is in scope
}
</code></pre></blockquote>

<p>
With these new declarations,
the names declared would decay to the appropriate type:
</p>
<ul>
<li>namespace scope to function pointer</li>
<li>class scope static to function pointer</li>
<li>class scope non-static to member pointer</li>
<li>block scope <code>[]</code> <var>lambda-introducer</var>
to function pointer</li>
<li>block scope with other forms of <var>lambda-introducer</var>
to closure object</li>
</ul>

<p>
Note that the above decay results in slightly different semantics
for the following two lines:
</p>
<blockquote><pre><code>
[]   f     (int z)-&gt;int { return x+z; }
auto f = [](int z)-&gt;int { return x+z; };
</code></pre></blockquote>
<p>
The former defines a function
and will decay to a function pointer.
The latter uses a lambda expression to initialize
a variable containing a closure object
and will not decay to a function pointer.
</p>

<p>
Finally, we come to the issue of compatiblity
with existing block-local function declarations.
Such declarations refer to a function at namespace scope
rather than to a function at block scope.
Use of such semantics has always seemed inconsistent,
and so we propose to make the new syntax always declare a block-local function.
Thus, forward local function declarations are reasonable.
</p>
<blockquote><pre><code>
int h(int b) {
    []even(unsigned n)-&gt;bool;
    []odd(unsigned n)-&gt;bool;
    []even(unsigned n)-&gt;bool {
        if ( n == 0 ) return true;
        else return odd(n-1);
    }
    []odd(unsigned n)-&gt;int {
        if ( n == 0 ) return false;
        else return even(n-1);
    }
}
</code></pre></blockquote>


<h2>Proposed Wording</h2>

<p>
The proposed wording shows changes
from working draft standard
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2723.pdf">N2723</a>.
</p>


<h3>3.3.1 Point of declaration [basic.scope.pdecl]</h3>

<p>
In paragraph 9, edit
</p>
<blockquote>
<p>
[<i>Note:</i>
friend declarations refer to functions or classes
that are members of the nearest enclosing namespace,
but they do not introduce new names into that namespace (7.3.1.2).
<del>Function declarations at block scope
and object declarations with the <code>extern</code> specifier at block scope
</del>
<ins>The following kinds of block scope declarations</ins>
refer to delarations
that are members of an enclosing namespace,
but they do not introduce new names into that scope.
<ul>
<li>
<ins>function declarations 
without a <var>simple-type-specifier</var> of
<var>lambda-introducer</var>,</ins>
</li>
<li>
<ins>function declarations 
with a <var>simple-type-specifier</var> of
<var>lambda-introducer</var>
and with an <code>extern</code> specifier,</ins>
</li>
<li>
<ins>object declarations with the <code>extern</code> specifier.</ins>
</li>
</ul>
<p>
&mdash;<i>end note</i>]
</p>
</blockquote>

<h3>3.5 Program and linkage [basic.link]</h3>

<p>
In paragraph 6, edit
</p>

<blockquote>
<p>
The name of a function declared in block scope
<ins>without a <var>simple-type-specifier</var>
of <var>lambda-introducer</var></ins>,
and the name of <ins>a function or</ins> an object
declared by a block scope extern declaration,
have linkage.
<ins>If a declared function has no linkage, the program is ill-formed.</ins>
If there is a visible declaration of an entity with linkage
having the same name and type,
ignoring entities declared outside the innermost enclosing namespace scope,
the block scope declaration
declares that same entity
and receives the linkage of the previous declaration.
If there is more than one such matching entity, the program is ill-formed.
Otherwise, if no matching entity is found,
the block scope entity receives external linkage.
</p>
</blockquote>

<h3>7.1.6.2 Simple type specifiers [dcl.type.simple]</h3>

<p>
In paragraph 1, edit
</p>

<blockquote>
<p>
The simple type specifiers are
</p>
<blockquote>
<dl>
<dt><var>simple-type-specifier:</var></dt>
<dd><code>::</code><var><sub>opt</sub></var>
<var>nested-name-specifier<sub>opt</sub> type-name</var></dd>
<dd><code>::</code><var><sub>opt</sub></var>
<var>nested-name-specifier<sub>opt</sub></var>
<code>template</code> <var>simple-template-id</var></dd>
<dd><code>char</code></dd>
<dd><code>char16_t</code></dd>
<dd><code>char32_t</code></dd>
<dd><code>wchar_t</code></dd>
<dd><code>bool</code></dd>
<dd><code>short</code></dd>
<dd><code>int</code></dd>
<dd><code>long</code></dd>
<dd><code>signed</code></dd>
<dd><code>unsigned</code></dd>
<dd><code>float</code></dd>
<dd><code>double</code></dd>
<dd><code>void</code></dd>
<dd><code>auto</code></dd>
<dd><ins><var>lambda-introducer</var></ins></dd>
<dd><code>decltype (</code> <var>expression</var> <code>)</code></dd>
</dl>
</blockquote>
</blockquote>

<p>
In paragraph 2, edit
</p>

<blockquote>
<p>
The <code>auto</code> specifier
is a placeholder for a type to be deduced (7.1.6.4).
<ins>The <var>lambda-introducer</var> specifier
is used only for a late-specified return type (8.3.5 [dcl.fct]),
and shall have the form <code>[]</code>.</ins>
The other <var>simple-type-specifiers</var>
specify either a previously-declared user-defined type
or one of the fundamental types (3.9.1).
Table 9 summarizes the valid combinations
of <var>simple-type-specifiers</var> and the types they specify.
</p>
</blockquote>

<p>
In table 9, edit
</p>

<blockquote>
<table>
<caption>Table 9: <var>simple-type-specifiers</var>
and the types they specify</caption>
<tbody>
<tr><th>Specifier(s)</th><th>Type</th></tr>
<tr><td><var>type-name</var></td><td>the type named</td></tr>
<tr><td><code>char</code></td><td>"char"</td></tr>
<tr><td><code>unsigned char</code></td><td>"unsigned char"</td></tr>
<tr><td><code>signed char</code></td><td>"signed char"</td></tr>
<tr><td><code>char16_t</code></td><td>"char16_t"</td></tr>
<tr><td><code>char32_t</code></td><td>"char32_t"</td></tr>
<tr><td><code>bool</code></td><td>"bool"</td></tr>
<tr><td><code>unsigned</code></td><td>"unsigned int"</td></tr>
<tr><td><code>unsigned int</code></td><td>"unsigned int"</td></tr>
<tr><td><code>signed</code></td><td>"int"</td></tr>
<tr><td><code>signed int</code></td><td>"int"</td></tr>
<tr><td><code>int</code></td><td>"int"</td></tr>
<tr><td><code>unsigned short int</code></td><td>"unsigned short int"</td></tr>
<tr><td><code>unsigned short</code></td><td>"unsigned short int"</td></tr>
<tr><td><code>unsigned long int</code></td><td>"unsigned long int"</td></tr>
<tr><td><code>unsigned long</code></td><td>"unsigned long int"</td></tr>
<tr><td><code>unsigned long long int</code></td><td>"unsigned long long int"</td></tr>
<tr><td><code>unsigned long long</code></td><td>"unsigned long long int"</td></tr>
<tr><td><code>signed long int</code></td><td>"long int"</td></tr>
<tr><td><code>signed long</code></td><td>"long int"</td></tr>
<tr><td><code>signed long long int</code></td><td>"long long int"</td></tr>
<tr><td><code>signed long long</code></td><td>"long long int"</td></tr>
<tr><td><code>long long int</code></td><td>"long long int"</td></tr>
<tr><td><code>long long</code></td><td>"long long int"</td></tr>
<tr><td><code>long int</code></td><td>"long int"</td></tr>
<tr><td><code>long</code></td><td>"long int"</td></tr>
<tr><td><code>signed short int</code></td><td>"short int"</td></tr>
<tr><td><code>signed short</code></td><td>"short int"</td></tr>
<tr><td><code>short int</code></td><td>"short int"</td></tr>
<tr><td><code>short</code></td><td>"short int"</td></tr>
<tr><td><code>wchar_t</code></td><td>"wchar_t"</td></tr>
<tr><td><code>float</code></td><td>"float"</td></tr>
<tr><td><code>double</code></td><td>"double"</td></tr>
<tr><td><code>long double</code></td><td>"long double"</td></tr>
<tr><td><code>void</code></td><td>"void"</td></tr>
<tr><td><code>auto</code></td><td>type to be deduced</td></tr>
<tr><td><ins><var>lambda-introducer</var></ins></td><td><ins>the late-specified return type</ins></td></tr>
<tr><td><code>decltype(</code><var>expression</var><code>)</code></td><td>the type as defined below</td></tr>
</tbody>
</table>
</blockquote>

<h3>7.1.6.4 <code>auto</code> specifier [dcl.spec.auto]</h3>

<p>
Remove paragraph 1.
</p>

<blockquote>
<p>
<del>The <code>auto</code> <var>type-specifier</var>
signifies that the type of an object being declared
shall be deduced from its initializer
or specified explicitly at the end of a function declarator.</del>
</p>
</blockquote>

<p>
Remove paragraph 2.
</p>

<blockquote>
<p>
<del>The <code>auto</code> <var>type-specifier</var>
may appear with a function declarator
with a late-specified return type (8.3.5)
in any context where such a declarator is valid,
and the use of <code>auto</code>
is replaced by the type specified at the end of the declarator.</del>
</p>
</blockquote>

<p>
Edit paragraph 3.
</p>

<blockquote>
<p>
<del>Otherwise, the type of the object is deduced from its initializer.</del>
<ins>The <code>auto</code> <var>type-specifier</var>
signifies that the type of an object being declared
shall be deduced from its initializer.</ins>
The name of the object being declared
shall not appear in the initializer expression.
The auto type-specifier is allowed when declaring objects
in a block (6.3),
in namespace scope (3.3.5),
and in a for-init-statement (6.5.3).
The decl-specifier-seq shall be followed
by one or more init-declarators,
each of which shall have a non-empty initializer
of either of the following forms:
</p>
<blockquote>
<p>
<code>=</code> <var>assignment-expression</var>
<br><code>(</code> <var>assignment-expression</var> <code>)</code>
</p>
</blockquote>
</blockquote>

<h3>8.3.5 Functions [dcl.fct]</h3>

<p>
In paragraph 2, 
</p>

<blockquote>
<p>
In a declaration <code>T D</code> where <code>D</code> has the form
</p>
<blockquote>
<p>
<code>D1 (</code> <var>parameter-declaration-clause</var> <code>)</code>
<var>cv-qualifier-seq<sub>opt</sub> ref-qualifier<sub>opt</sub>
exception-specification<sub>opt</sub></var>
<code>-&gt;</code> <var>type-id</var>
</p>
</blockquote>
<p>
and the type of the contained <var>declarator-id</var>
in the declaration <code>T D1</code>
is "<var>derived-declarator-type-list</var> <code>T</code>,"
<code>T</code> shall be the single <var>type-specifier</var>
<del><code>auto</code></del>
<ins><var>lambda-introducer</var></ins>
and the <var>derived-declarator-type-list</var> shall be empty.
<del>Then the</del> <ins>The</ins> type
of the <var>declarator-id</var> in <code>D</code>
is "function of
<code>(</code><var>parameter-declaration-clause</var><code>)</code>
<var>cv-qualifier-seq<sub>opt</sub> ref-qualifier<sub>opt</sub></var>
returning <var>type-id</var>".
Such a function type has a <dfn>late-specified</dfn> return type.
</p>
</blockquote>

<p>
Note that N2761 may add attribute specifiers to the declaration form above.
That edit does not conflict.
Note that N2757 may remove
"and the <var>derived-declarator-type-list</var> shall be empty"
in the text above.
</p>

<p>
In paragraph 3,
</p>

<blockquote>
<p>
The <var>type-id</var> in this form
includes the longest possible sequence of <var>abstract-declarator</var>s.
[<i>Note:</i>
This resolves the ambiguous binding of array and function declarators.
[<i>Example:</i>
</p>
<blockquote>
<p>
<code><del>auto</del> <ins>[]</ins> f()-&gt;int(*)[4];</code>
<i>// function returning a pointer to array[4] of int</i>
<br><i>// not function returning array[4] of pointer to int</i>
</p>
</blockquote>
<p>
&mdash;<i>end example</i>]
&mdash;<i>end note</i>]
</p>
</blockquote>

<p>
Within paragraph 12, edit
</p>

<blockquote>
<p>
[<i>Note:</i>
typedefs and late-specified return types
are sometimes convenient when the return type of a function is complex.
For example, the function <code>fpif</code> above
could have been declared
</p>
<blockquote><pre><code>
typedef int IFUNC(int);
IFUNC* fpif(int);
</code></pre></blockquote>
<p>
or
</p>
<blockquote><pre><code>
<del>auto</del> <ins>[]</ins> fpif(int)-&gt;int(*)(int)
</code></pre></blockquote>
<p>
A late-specified return type
is most useful for a type that would be more complicated to specify
before the <var>declarator-id</var>:
</p>
<blockquote><pre><code>
template &lt;class T, class U&gt;
<del>auto</del> <ins>[]</ins> add(T t, U u) -&gt; decltype(t + u);
</code></pre></blockquote>
<p>
rather than
</p>
<blockquote><pre><code>
template &lt;class T, class U&gt;
decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
</code></pre></blockquote>
<p>
&mdash;<i>end note</i>]
</p>
</blockquote>

</body>
</html>
