1. Changelog
1.1. Revision 0 - December 16th, 2024
-
Initial Release! 🎉
2. Introduction and Motivation
C99 introduced
, which is the string name of the function. Microsoft added
to provide another way to get the string name of the function call. But, none of the compilers ever added a way to refer to the current function, despite the need for it appearing it macros and other places that wished to implement e.g. Tail Recursion or other traits in a function-agnostic ways. Macro authors forced users to pass in the name of the function so it could be properly recursed on, but this is slightly cumbersome.
Recently,
and -- at the behest of the Committee to rename it --
have both shown up in Celeste’s "C Extensions to Support Generalized Functions Calls, v3.5" [N3315]. It’s specification is there in the wording but it only exists to describe tail-calling. Some support was expressed for lifting it out and making it its own entity rather than something that existed purely in the wording itself.
This paper is the lift out, implementing
as a keyword.
3. Design
The design for this is, thankfully, very simple and easy:
is a keyword/identifier that represents the current function invocation the compiler is in. This is implementable very simple in the compiler frontend by simply performing an identifier substitution for the name of the function being translated, and erroring if at file scope.
is a "function designator" in C Standardese terms, that represents the current function. It is a constraint violation to call this in
(
is not allowed to recurse on itself, or rather it is undefined behavior) and it is a constraint violation for it to be used at any non-block scope. The wording tries to make this easy by making it part of the block grammar, banning it for existing at file scope.
3.1. Keyword Name
We do not care what this is called. This has 3 popular names:
-
(C++ using the "usual" name for its "Deducing This" feature, most users in C and C++-derived languages by convention)self -
/this
(C++, sometimes JavaScript when* this
is not rebound in strange ways)this -
(Clojure and other LISP-style functional languages)recur
and
are common identifiers in some places, which is what resulted in N3315 to rename it.
and
are fine.
is what this proposal settled on, using the double underscores to have it exist in a space similar to an identifier, even if the intent is to exist as a keyword.
As stated earlier, we do not care what it is called, so long as it exists. Suggestions are welcome and any name will do just fine.
4. Wording
This wording is relative to C’s latest working draft.
📝 Editor’s Note: The ✨ characters are intentional. They represent stand-ins to be replaced by the editor.
4.1. Add the new keyword __self_func
to §6.4.2
4.2. Add a new grammar terminal in the postfix-expression grammar production of §6.5.3.1 "__self_func
Syntax
1 postfix-expression:
primary-expression
postfix-expression
*expression
[
] postfix-expression
argument-expression-listopt
(
) postfix-expression
identifier
. postfix-expression
identifier
-> postfix-expression
++ postfix-expression
-- compound-literal
__self_func
4.3. Add a new section §6.5.3.✨ "__self_func
6.5.3.✨
__self_func Constraints
shall appear in a function body.
__self_func Semantics
is the function designator (6.3.3.1) of the function it is used in.
__self_func EXAMPLE A program refers to the enclosing function even when the name is not directly known.
#include <stdlib.h>#include <stddef.h>#include <stdio.h>bool f ( int tries , const char * fn ) { #define MAX_TRIES 30 #define RE_DO(TRIES, ...) if (TRIES >= MAX_TRIES) goto TOO_MANY_TRIES; return __self_func(TRIES + 1, __VA_ARGS__); if ( fn == nullptr ) return false; size_t fnlen = strlen ( fn ); if ( fnlen < 1 ) return false; FILE * f = fopen ( fn ); if ( ! f ) { fn [ fnlen - 1 ] = '0' + tries ; RE_DO ( tries , fn ); } // found the first proper f, // use it fclose ( f ); return true; TOO_MANY_TRIES : if ( f ) fclose ( f ); return false; }