Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Blocking] Function keyword: fn or func? #463

Closed
jonmeow opened this issue Apr 14, 2021 · 9 comments · Fixed by #438
Closed

[Blocking] Function keyword: fn or func? #463

jonmeow opened this issue Apr 14, 2021 · 9 comments · Fixed by #438
Assignees
Labels
leads question A question for the leads team

Comments

@jonmeow
Copy link
Contributor

jonmeow commented Apr 14, 2021

#438 proposes a syntax for functions. Although fn has been used as a placeholder, the proposal is intended to formalize the format.

The "Function keyword" alternative goes over options in more depth. The fn or func conclusion is based on discussion on Discord.

I've asked Chandler for his leaning on this, he's following up with research and for a leads decision. This issue is tracking that discussion. :)

@jonmeow jonmeow assigned chandlerc and unassigned chandlerc Apr 14, 2021
@jonmeow jonmeow linked a pull request Apr 14, 2021 that will close this issue
@jonmeow jonmeow changed the title Function keyword: fn or func? [Blocking] Function keyword: fn or func? Apr 19, 2021
@chandlerc
Copy link
Contributor

One set of concerns with fn is that there is at least the potential for associations we don't want here -- both due to pronunciation and other things named "FN". However, it isn't clear if this is just a potential issue or would be an issue in practice. I reached out to some folks who have worked in the Rust community for a long period of time to understand if anything like this has come up given that fn is used there and the community seems very likely to notice and care about similar things. Their answer was a pretty solid "nope, never an issue in practice". In general, there seemed to be no material regrets from Rust's use of the keyword. I view this as a strong signal we can largely focus on more basic readability and other considerations.

On that note, I want to surface one remaining concern that I have with fn (and equally with func).

First, why does this keyword matter that much? I want us to consider this choice quite carefully because function declarations are a primary component of API descriptions and so extremely frequently read and scanned by humans. Readability, scanning, skimming, and such concerns are very large for this specific keyword.

However, a large fraction (likely a majority?) of functions that are read so often will in fact be methods. While the original placeholder overview suggested syntax like fn Size(Ptr(Self) this) -> Int where this is the object parameter, more recent examples have steadily moved toward a different syntax:

  method (Ptr(Self) this) Size() -> Int;

Here, the introducer would be method, not fn (or func, or ...). And in reality we should be considering a mixture:

struct Container {
  // A "static" function to create objects of this type.
  fn Create(Int num_elements) -> Container;

  // Some methods.
  method (Ptr(Container) this) Size() -> Int;
  method (Ptr(Container) this) Reverse();
  method (Ptr(Container) this) Append(Widget w);
  method (Ptr(Container) this) Pop() -> Widget;
  // ...
}

I'm not thrilled with the use of fn and method here. They don't seem to fit together. The same (for me) holds for func.

So I think we either need to the same introducer (fn or func) everywhere (even when using the object parameter syntax), or I think we need to think about what pair of introducers would make sense to have for non-methods and methods. At the moment, function and method seem the most natural to me, but this is the first time I've really started thinking about the mixture of these.

Thoughts? @carbon-language/carbon-leads

@josh11b specifically as I know he's thought a lot about the method syntax.

@fowles
Copy link

fowles commented Apr 22, 2021

I really appreciate the brevity of fn and would argue for using fn for both free functions and methods.

given how common we expect methods to be, even (Ptr(Self) this) feels like a lot of ceremony for something so common

@chandlerc
Copy link
Contributor

FWIW, I'm also very tempted by the brevity of fn and the idea of just using fn for both given that it remains syntactically unambiguous. But wanted to call out this concern and hear from folks who have been poking at methods more heavily in example code than I have.

@austern
Copy link
Contributor

austern commented Apr 22, 2021

I would turn the question around: is there any well known language that has both functions and methods, and that has introducers for function definitions, and that uses a different introducer for methods than for functions?

I'm not aware of any. What we're thinking of for Carbon method definitions (both in structs and in interfaces) looks an awful lot like Go and Rust. Go uses func both for functions and methods, and Rust uses fn for both. Python is slightly different, but Python, too, uses def for both.

Whatever introducer we choose, I really want to have just one of them instead of two.

@zygoloid
Copy link
Contributor

I would turn the question around: is there any well known language that has both functions and methods, and that has introducers for function definitions, and that uses a different introducer for methods than for functions?

Objective-C uses + for class methods (that we'd call functions) and - for instance methods. (And a completely different syntax for free functions.)

Whatever introducer we choose, I really want to have just one of them instead of two.

I think I agree. I don't immediately see an issue with replacing method with fn in @chandlerc's example:

struct Container {
  // A "static" function to create objects of this type.
  fn Create(Int num_elements) -> Container;

  // Some methods.
  fn (Ptr(Container) this) Size() -> Int;
  fn (Ptr(Container) this) Reverse();
  fn (Ptr(Container) this) Append(Widget w);
  fn (Ptr(Container) this) Pop() -> Widget;
  // ...
}

... though I think this is still more verbose than I'd prefer.

At the risk of heading off-topic, I also wonder if a declaration syntax mirroring the use syntax would be better here:

  fn (Ptr(Container) this).Size() -> Int;

@josh11b
Copy link
Contributor

josh11b commented Apr 22, 2021

I considered the ., but it runs into an inconsistency since in this case:

fn (Ptr(Container) this).Size() -> Int;

it should actually be an arrow, since the this is declared as a pointer:

fn (Ptr(Container) this)->Size() -> Int;

Terrible idea:

// Method taking `Self this`
fn .Size() -> Int;
// Method taking `Ptr(Self) this`
fn ->Reverse();

@chandlerc
Copy link
Contributor

I'd really like to focus this thread on just the introoducer keyword please. =D I can see this starting to drift and I'd like too pull it back.

@josh11b josh11b mentioned this issue Apr 23, 2021
@chandlerc
Copy link
Contributor

I think based on the "thumbs up" above and posts that we have consensus here to use fn as the keyword for both functions and methods.

Would like confirmation from @zygoloid and @KateGregory and I think we can resolve this.

@chandlerc
Copy link
Contributor

Have confirmation from @KateGregory and already had a private discussion with @zygoloid, so I think I'm being too conservative here. =D I think all of the leads are clearly aligned around the answer here:

  • Use fn as the introducer.
  • Likely for both functions and methods, and we'll finish sorting that out in Method syntax #494.

@jonmeow jonmeow added the leads question A question for the leads team label Aug 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
leads question A question for the leads team
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants