diff --git a/proposals/README.md b/proposals/README.md index 1cdb103584cef..ca3bbc9f2bc96 100644 --- a/proposals/README.md +++ b/proposals/README.md @@ -51,6 +51,7 @@ request: - [0353 - `for` loops](p0353.md) - [0415 - Syntax: `return`](p0415.md) - [0426 - Governance & evolution revamp](p0426.md) +- [0438 - Functions](p0438.md) - [0444 - GitHub Discussions](p0444.md) - [0447 - Generics terminology](p0447.md) diff --git a/proposals/p0438.md b/proposals/p0438.md new file mode 100644 index 0000000000000..d0cf9019c1f95 --- /dev/null +++ b/proposals/p0438.md @@ -0,0 +1,471 @@ +# 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) + - [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](https://github.com/carbon-language/carbon-lang/blob/trunk/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`.