We currently have placeholder guidance on functions. The intent of this proposal is to establish agreement on the basics, providing a baseline for future evolution.
C++ syntax for function declarations comes in two forms:
std::int64_t Sum(std::int64_t a, std::int64_t b) {
return a + b;
}
// Or with trailing return type syntax:
auto Sum(std::int64_t a, std::int64_t b) -> std::int64_t {
return a + b;
}
Bodies are always wrapped by braces.
To summarize keyword use from other languages:
-: Objective-Cdef: Python and Rubyfn: Rustfun: Kotlinfunc: Go and Swiftfunction: JavaScript, MatLab, PHP, R, and TypeScriptFor exhaustive function examples:
C#
int Sum(int a, int b) {
return a + b;
}
Go
func add(a int, b int) int {
return a + b
}
Java
Int Sum(Int a, Int b) {
return a + b;
}
JavaScript
function Sum(a, b) {
return a + b;
}
Kotlin
fun add(a: Int, b: Int): Int {
return a + b
}
Matlab
function s = sum(a,b)
s = a+b;
end
Objective-C
- (int)sum:(int)a
(int)b {
return a + b;
}
PHP
function sum(int $a, int $b) {
return $a + $b;
}
Python
def sum(a, b):
return a + b
def sum(a: int, b: int) -> int:
return a + b
R
sum <- function(a, b) {
a + b
}
Ruby
def sum(a, b)
return a + b
end
Rust
fn sum(a: i64, b: i64) -> i64 {
a + b
}
Swift
func sum(a: Int, b: Int) -> Int {
return a + b
}
TypeScript
function sum(a: number, b: number): number {
return a + b;
}
Forward declarations of functions are largely unique to C++. Objective-C also has this. However, most other languages being discussed do not.
Function declarations and definitions should look like:
fn function name ( type identifier [ , type identifier ]... ) [
-> return type ] [ { body } | ; ]
Arguments should be comma-separated and imitate
var syntax,
although var itself is not used.
For example:
fn Sum(Int a, Int b) -> Int {
<body>
}
fn UnusedArgument(Int _) -> Int {
<body>
}
The return type may optionally be omitted if (). For example, these two
function declarations both return ():
fn Print(String s) -> ();
fn Print(String s);
Forward declarations will be supported in order to support separation of API and implementation, as explained in code and name organization. For example:
package Math api;
fn Sum(Int a, Int b) -> Int;
Forward declarations will experimentally only be allowed in api files, and
only when the definition is in the library's impl file. The intent is to
minimize use, consistent with most other languages that have no forward
declaration support at all.
Carbon needs functions in order to be writable by developers. That functionality needs a syntax.
Relevant goals are:
3. Code that is easy to read, understand, and write:
5. Fast and scalable development: The addition of a keyword should make parsing easy.
7. Interoperability with and migration from existing C++ code: Keeping syntax close to C++ will make it easier for developers to transition.
C++ supports forward declaring functions in a .cpp file, and this may be
useful for handling interdependencies between functions. In Carbon, we should
instead aim to allow having a function able to call a function defined later in
the same file without requiring a forward declaration.
Advantages:
Disadvantages:
We'll need to evaluate how this works. There is tracked by #472. This does not need to block this proposal, as we can allow it later if that's the decision; it may also be helpful to give more time to consider how name lookup should work.
Argument names are required under this proposal. It's likely that developers will want a way to indicate unused arguments. This is tracked by #476.
We may have anchored on fn without much consideration. A key piece of this
proposal is to suggest reconsidering the choice, even if we end up with the
same.
Advantages:
Disadvantages:
auto to indicate a "type".There's a consensus that some keyword should be used in order to simplify parsing, so this option is not expected to receive much support.
- (dash)Advantages:
+ and we could echo that too.Disadvantages:
- operator.Although this alternative is mentioned, it is not expected to receive much support due to its readability problem.
defAdvantages:
Disadvantages:
def is presumably short for "define", which may not be as obvious as a
"function" derivative.fnAdvantages:
Disadvantages:
funAdvantages:
var as a push towards three letter abbreviations.
let may be used in a similar way, although it's not an abbreviation.Disadvantages:
When wrapping function definitions, the function name and wrapped types would end up on the same column when indenting by 4 spaces. These use the same casing, so it may make it slower to understand code.
For example:
fun Print(
String message) {
...
}
// Similar confusion if the body of the function is indented 4 spaces.
fun Print(String message) {
SomeFunctionCall();
...
}
This is also true for var, but wrapping arguments is expected to be
more common for functions, and the casing more likely to match.
funcAdvantages:
Disadvantages:
functionAdvantages:
Disadvantages:
fn and func are the favored options:
fn is clearly shorter than func. Both are shorter than "function".var, and something like mut or
const seems likely. ptr is possible.
func is consistent with abbreviation by removing letters at the
end.fn is more consistent with abbreviations like ptr that remove
letters in the middle, but a three letter abbreviation like fcn
would be more consistent.fn deletes letters in the middle of "function", func does not.func is used by Go and Swift, both of which are common languages.
func is very searchable.fn is only used by Rust, which by most measures has less adoption than
either Go or Swift at present. However, it is used in
Hungarian notation,
so some C++ developers will be familiar with fn for function pointers.
func could be as "funk", defined as a music genre or state of
depression.fn could be as:
Note that both are argued here as reasonable solutions that would satisfy many.
This was asked on
#463. We are using
fn.