<!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 N2582 = 08-0092 - 2008-03-16
</p>

<p>
Lawrence Crowl, crowl@google.com, Lawrence@Crowl.org
<br>
Alisdair Meredith, alisdair.meredith@codegear.com
</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 also introduces named lambdas.
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>
Furthermore,
in keeping with discussion at the February 2008 meeting,
we adjust the syntax of the new function syntax in
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2541.html">N2541</a>
to prevent complicated declarators.
Such declarators are inconsistent with lambda expressions.
</p>

<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 and named lambdas.
(We do not propose to add that requirement to lambda expressions.)
</p>

<h2>Semantic Regularization</h2>

<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)->int { return x+z; }
auto f = [](int z)->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 an editing draft preliminary to the March 2008 mailing.
The base text does not form an officially accepted draft.
Earlier drafts do not have the requisite text.
</p>

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

<p>
In paragraph 9, edit
</p>
<blockquote>
<p>
[<i>Note:</i>
<code>friend</code> 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).
<ins>Function declarations at block scope
with a <var>simple-type-specifier</var> of
<var>lambda-introducer</var>
introduce a new name into that scope,
and the <code>extern</code> specifier is not permitted.</ins>
<del>Function</del> <ins>Other function</ins> declarations at block scope
and object declarations with the <code>extern</code> specifier at block scope
refer to delarations
that are members of an enclosing namespace,
but they do not introduce new names into that scope.
&mdash;<i>end note</i>]
</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
indicates a late-specified return type (8.3.5 [dcl.fct]).
A <var>lambda-introducer</var> other than <code>[]</code>
may only be specified at block scope.</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><del><var>type-name</var></del></td><td><del>the type named</del></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>Chapter 8 Declarators [dcl.decl]</h3>

<p>
In summary, paragraph 4 edits are:
</p>

<ul>
<li>
replacing the <var>direct-declarator</var>
of a new-style function with <var>declarator-id</var>,
</li>
<li>
moving the new-style function from <var>direct-declarator</var>
to <var>declarator</var>, and
</li>
<li>
factoring out the common function declarator grammar phrase.
</li>
</ul>

<p>
The edits to paragraph 4 are:
</p>

<blockquote>
<dl>

<dt><var>declarator:</var></dt>
<dd>
<var>direct-declarator</var>
</dd>
<dd>
<var>ptr-operator declarator</var>
</dd>
<dd>
<ins><var>declarator-id</var> <var>parameters-and-qualifiers</var>
<code>-&gt;</code> <var>type-id</var></ins>
</dd>

<dt><var>direct-declarator:</var></dt>
<dd>
<var>declarator-id</var>
</dd>
<dd>
<del><var>direct-declarator</var>
<code>(</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></del>
</dd>
<dd>
<ins><var>direct-declarator</var> <var>parameters-and-qualifiers</var></ins>
</dd>
<dd>
<del><var>direct-declarator</var>
<code>(</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></del>
</dd>
<dd>
<var>direct-declarator</var>
<code>[</code> <var>constant-expression<sub>opt</sub></var> <code>]</code>
</dd>
<dd>
<code>(</code> <var>declarator</var> <code>)</code>
</dd>

<dt><ins><var>parameters-and-qualifers:</var></ins></dt>
<dd>
<ins><code>(</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></ins>
</dd>

<dt><var>ptr-operator:</var></dt>
<dd>
<code>*</code> <var>cv-qualifier-seq<sub>opt</sub></var>
<dd>
<code>&amp;</code>
</dd>
<dd>
<code>&amp;&amp;</code>
</dd>
<dd>
<code>::</code><var><sub>opt</sub></var>
<var>nested-name-specifier</var> <code>*</code>
<var>cv-qualifier-seq<sub>opt</sub></var>
</dd>

<dt><var>cv-qualifier-seq:</var></dt>
<dd>
<var>cv-qualifier cv-qualifier-seq<sub>opt</sub></var>
</dd>

<dt><var>cv-qualifier:</var></dt>
<dd>
<code>const</code>
</dd>
<dd>
<code>volatile</code>
</dd>

<dt><var>ref-qualifier:</var></dt>
<dd>
<code>&amp;</code>
</dd>
<dd>
<code>&amp;&amp;</code>
</dd>

<dt><var>declarator-id:</var></dt>
<dd>
<code>...</code><var><sub>opt</sub></var> <var>id-expression</var>
</dd>
<dd>
<code>::</code><var><sub>opt</sub></var>
<var>nested-name-specifier<sub>opt</sub> class-name</var>
</dd>

</dl>
</blockquote>

<h3>8.1 Type names [dcl.name]</h3>

<p>
Within paragraph 1, edit
</p>
<blockquote>
<dl>

<dt><var>abstract-declarator:</var></dt>
<dd>
<var>ptr-operator declarator<sub>opt</sub></var>
</dd>
<dd>
<var>direct-abstract-declarator</var>
</dd>
<dd>
<code>...</code>
</dd>
<dd>
<ins><var>parameters-and-qualifiers</var>
<code>-&gt;</code> <var>type-id</var></ins>
</dd>

<dt><var>direct-abstract-declarator:</var></dt>
<dd>
<del><var>direct-abstract-declarator</var>
<code>(</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></del>
</dd>
<dd>
<var>direct-abstract-declarator</var> <var>parameters-and-qualifiers</var>
</dd>
<dd>
<del><var>direct-abstact-declarator</var>
<code>(</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></del>
</dd>
<dd>
<var>direct-abstact-declarator</var>
<code>[</code> <var>constant-expression<sub>opt</sub></var> <code>]</code>
</dd>
<dd>
<code>(</code> <var>abstact-declarator</var> <code>)</code>
</dd>

</dl>
</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.
<ins>If the form of the <var>lambda-introducer</var> is <code>[]</code>,
then</ins>
<del>Then</del> the 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.
<ins>If the form of the <var>lambda-introducer</var> is
not <code>[]</code>,
then the type of the <var>declarator-id</var> in <code>D</code>
is that of a closure object
as specified in (5.1.1 [expr.prim.lambda]).
That is, the declaration is equivalent to
</ins>
</p>
<blockquote>
<p>
<code>auto D1 =</code> <var>lambda-introducer</var>
<code>(</code> <var>parameter-declaration-clause</var> <code>)</code>
<var>exception-specification<sub>opt</sub></var>
<code>-&gt;</code> <var>type-id</var>
</p>
</blockquote>
</blockquote>

<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>

<h3>8.4 Function definitions [dcl.fct.def]</h3>

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

<blockquote>
<p>
The declarator in a function-definition shall have 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>
as described in 8.3.5.
A function
<ins>with a <var>simple-type-specifier</var> of <var>lambda-introducer</var>
may be defined at namespace, class, or block scope.
Other functions</ins>
shall be defined only in namespace or class scope.
</p>
</blockquote>

</body>
</html>
