# Functions [Pull request](https://github.com/carbon-language/carbon-lang/pull/438) ## Table of contents - [Problem](#problem) - [Background](#background) - [C++ syntax](#c-syntax) - [Other languages](#other-languages) - [Forward declarations](#forward-declarations) - [Proposal](#proposal) - [Functions](#functions-1) - [Forward declarations](#forward-declarations-1) - [Rationale based on Carbon's goals](#rationale-based-on-carbons-goals) - [Open questions](#open-questions) - [Calling functions defined later in the same file](#calling-functions-defined-later-in-the-same-file) - [Optional argument names](#optional-argument-names) - [Alternatives considered](#alternatives-considered) - [Function keyword](#function-keyword) - [Type](#type) - [`-` (dash)](#--dash) - [`def`](#def) - [`fn`](#fn) - [`fun`](#fun) - [`func`](#func) - [`function`](#function) - [Conclusion](#conclusion) ## Problem We currently have [placeholder guidance on functions](/docs/design/functions.md). The intent of this proposal is to establish agreement on the basics, providing a baseline for future evolution. ## Background ### C++ syntax C++ syntax for function declarations comes in two forms: ```cpp 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. ### Other languages To summarize keyword use from other languages: - Type: C# and Java - `-`: Objective-C - `def`: Python and Ruby - `fn`: Rust - `fun`: Kotlin - `func`: Go and Swift - `function`: JavaScript, MatLab, PHP, R, and TypeScript For exhaustive function examples: - C# ```csharp int Sum(int a, int b) { return a + b; } ``` - Go ```go func add(a int, b int) int { return a + b } ``` - Java ```java Int Sum(Int a, Int b) { return a + b; } ``` - JavaScript ```javascript function Sum(a, b) { return a + b; } ``` - Kotlin ```kotlin fun add(a: Int, b: Int): Int { return a + b } ``` - Matlab ```matlab function s = sum(a,b) s = a+b; end ``` - Objective-C ```objc - (int)sum:(int)a (int)b { return a + b; } ``` - PHP ```php function sum(int $a, int $b) { return $a + $b; } ``` - Python ```python def sum(a, b): return a + b def sum(a: int, b: int) -> int: return a + b ``` - R ```r sum <- function(a, b) { a + b } ``` - Ruby ```ruby def sum(a, b) return a + b end ``` - Rust ```rust fn sum(a: i64, b: i64) -> i64 { a + b } ``` - Swift ```swift func sum(a: Int, b: Int) -> Int { return a + b } ``` - TypeScript ```typescript function sum(a: number, b: number): number { return a + b; } ``` ### Forward declarations [Forward declarations](https://en.wikipedia.org/wiki/Forward_declaration) of functions are largely unique to C++. Objective-C also has this. However, most other languages being discussed do not. ## Proposal ### Functions 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](https://github.com/carbon-language/carbon-lang/pull/339), although `var` itself is not used. For example: ```carbon fn Sum(Int a, Int b) -> Int { } fn UnusedArgument(Int _) -> Int { } ``` The return type may optionally be omitted if `()`. For example, these two function declarations both return `()`: ```carbon fn Print(String s) -> (); fn Print(String s); ``` ### Forward declarations Forward declarations will be supported in order to support separation of API and implementation, as explained in [code and name organization](https://github.com/carbon-language/carbon-lang/tree/trunk/docs/design/code_and_name_organization). For example: ```carbon 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. ## Rationale based on Carbon's goals 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](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write): - Adding a keyword makes it easy for developers to visually identify functions. - Trailing return syntax should be easier to understand than C++'s older preceding return syntax. Only allowing one avoids requiring developers to recognize and choose between equivalent syntaxes. - [5. Fast and scalable development](/docs/project/goals.md#fast-and-scalable-development): The addition of a keyword should make parsing easy. - [7. Interoperability with and migration from existing C++ code](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code): Keeping syntax close to C++ will make it easier for developers to transition. ## Open questions ### Calling functions defined later in the same file 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: - Minimize accidents with forward declarations not matching implementation. - Fewer forward declarations for developers to find while reading. Disadvantages: - Shifts burden onto how code is parsed and executed. We'll need to evaluate how this works. There is tracked by [#472](https://github.com/carbon-language/carbon-lang/issues/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. ### Optional argument names 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](https://github.com/carbon-language/carbon-lang/issues/476). ## Alternatives considered ### Function keyword 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. #### Type Advantages: - Echoes C++, C#, and Java. - Simpler to write; a type will often be present for the return regardless. Disadvantages: - Makes function syntax more difficult to parse. - In C++, it's notable that functions with a trailing return still start with `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: - Echoes Objective-C instance method syntax. - Class methods use `+` and we could echo that too. - This is the most succinct option. Disadvantages: - Easy to miss, and hard to read as a result. - Might be ambiguous with the `-` operator. Although this alternative is mentioned, it is not expected to receive much support due to its readability problem. #### `def` Advantages: - Echoes Python and Ruby. Disadvantages: - `def` is presumably short for "define", which may not be as obvious as a "function" derivative. #### `fn` Advantages: - Echoes Rust. - The shortest "function" derivative. - Likely comes from the [fn key](https://en.wikipedia.org/wiki/Fn_key). Disadvantages: - Abbreviation by removing letters in the middle of a word is [disallowed by Carbon's C++ style](https://google.github.io/styleguide/cppguide.html#General_Naming_Rules). - Even though the abbreviation is in Wikipedia, it is not associated with [functions in programming](https://en.wikipedia.org/wiki/Subroutine). - Would likely be the only keyword abbreviated this way. #### `fun` Advantages: - Echoes Kotlin. - Could be used with `var` as a push towards three letter abbreviations. - Not clear there are other examples of three letter abbreviations. - `let` may be used in a similar way, although it's not an abbreviation. Disadvantages: - "fun" is a common English word and may be a mildly confusing choice as a result. - 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: ```carbon 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. #### `func` Advantages: - Echoes Go and Swift. Disadvantages: - The longest abbreviated form of "function". #### `function` Advantages: - Echoes JavaScript, MatLab, PHP, R, and TypeScript. - Clear meaning without any abbreviation. Disadvantages: - The longest "function" derivative. ### Conclusion `fn` and `func` are the favored options: - Desire to abbreviate "function": - `fn` is clearly shorter than `func`. Both are shorter than "function". - Consistency with other abbreviations: - We are using abbreviations like `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. - We are using [Google C++ style](https://google.github.io/styleguide/cppguide.html#General_Naming_Rules) as a base, which explicitly discourages abbreviating by deleting letters within a word. - `fn` deletes letters in the middle of "function", `func` does not. - Familiarity for developers: - `func` is used by Go and Swift, both of which are common languages. - [`func`](https://www.google.com/search?q=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](https://docs.microsoft.com/en-us/windows/win32/stg/coding-style-conventions), so some C++ developers will be familiar with `fn` for function pointers. - It's also used for the [Fn key](https://en.wikipedia.org/wiki/Fn_key), although assumptions about the meaning of "Fn" as abbreviation for "function" versus "F-number key" (as in F5) may mislead some developers. - [`fn`](https://www.google.com/search?q=fn) is difficult to search for. - Pronunciation: - Both may be pronounced as "function", but may also be pronounced by their abbreviation. - `func` could be as "funk", defined as a music genre or state of depression. - `fn` could be as: - "eff en", which has no direct meaning but could be misheard as "effing", or profanity. However, it's not clear that this potential mishearing is a pragmatic issue. - "fun", defined as enjoyment. Note that both are argued here as reasonable solutions that would satisfy many. This was asked on [#463](https://github.com/carbon-language/carbon-lang/issues/463). We are using `fn`.