mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 08:44:41 +01:00
Add statement syntax for function declarations (#438)
Add statement syntax (either `fn` or `func`, see proposal) for function declarations. - Follows C++-style trailing return syntax. Co-authored-by: Geoff Romer <gromer@google.com> Co-authored-by: josh11b <josh11b@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
Geoff Romer
josh11b
parent
29bf305539
commit
59add8c8de
@@ -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)
|
||||
|
||||
|
||||
@@ -0,0 +1,471 @@
|
||||
# Functions
|
||||
|
||||
<!--
|
||||
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
Exceptions. See /LICENSE for license information.
|
||||
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
-->
|
||||
|
||||
[Pull request](https://github.com/carbon-language/carbon-lang/pull/438)
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
## 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)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## 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 {
|
||||
<body>
|
||||
}
|
||||
|
||||
fn UnusedArgument(Int _) -> Int {
|
||||
<body>
|
||||
}
|
||||
```
|
||||
|
||||
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`.
|
||||
Reference in New Issue
Block a user