carbon-language / carbon-lang

Carbon Language's main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)
http://docs.carbon-lang.dev/
Other
32.25k stars 1.47k forks source link

Reconsider deduction specification list syntax #1778

Open OlaFosheimGrostad opened 2 years ago

OlaFosheimGrostad commented 2 years ago

The signature profile:

fn function_name[deduction_specification](parameter_list) -> type { … }

has some usability issues:

  1. Using '[…]' is not consistent with indexing semantics, this may have a negative impact on speed and accuracy when readers are trying to skim through/browse source code. Ideally symbols should not be used with multiple meanings as it has a negative impact on browsing performance.

  2. The signature does not clearly match the call syntax.

  3. When the deduction specification is long the formal parameters are pushed far away to the right, making it more difficult to quickly localize the argument list after having found the name.

  4. It fails to separate key information (name, formal parameters) from additional information (constraints) that are less critical when figuring out how to call the function.

Consider providing another syntax, either by replacing the current one or by providing syntax sugar.

Example:

fn function_name(parameter_list) -> type 
where deduction_specification { 
… 
}
h3har commented 2 years ago

I assume the ] in your example syntax is a typo?

h3har commented 2 years ago

The deduced argument list is used for more than just deduced generic and template arguments. It is used for 'self' arguments and I have seen discussion about using it for lambda capture lists (that's perhaps a separate issue). I think having to put 'self' arguments in a trailing where clause could be a bit cumbersome.

If the syntax was changed to a trailing where clause, perhaps the approach to 'self' arguments should be changed too? E.g., see Rust's syntax which puts self keyword as an optional first argument, making a function into a method instead of an associated function (like a static class function in C++). In Rust, the self argument is special in that you don't have to fully specify its type (although you can if necessary, e.g., in the case of Pin).

You could also argue that this self-as-first-argument syntax is more consistent, since self is not really a "deduced" parameter in the same sense as the type parameters - you still pass it to the function, it's just that the syntax is a bit different (it goes before the dot before the method name instead of as the first argument). I don't know if there are plans to adopt a Uniform Function Call Syntax (UFCS) in Carbon, but if so then having self (or me, or whatever) as the first argument makes even more sense.

OlaFosheimGrostad commented 2 years ago

I assume the ] in your example syntax is a typo?

Yes, thanks. (fixed)

OlaFosheimGrostad commented 2 years ago

You could also argue that this self-as-first-argument syntax is more consistent, since self is not really a "deduced" parameter in the same sense as the type parameters

Yes, and it is also more consistent with other languages, but I personally prefer that it is implicit as in most OO-languages: Simula, C++, Java, etc. I don't see that one gets any usability benefits from making it explicit, on the contrary…

(I guess their reasoning for having explict 'self' is that they don't have to put a qualifier in front of their factory functions, but that means they make the common case harder to write. This is usually considered a suboptimal design choice.)

emlai commented 2 years ago

There's a related discussion about improving the self parameter syntax, possibly moving it inside the parentheses: https://github.com/carbon-language/carbon-lang/discussions/1777.

chandlerc commented 2 years ago

First, a comment about the trailing where suggestion -- this is problematic as deduced types and parameters are needed within the signature of the explicit parameters and return, so it would seem somewhat awkward to place them afterward.

All that said, I think we're definitely interested in revisiting the entire syntax in this space. However, we'd like to do that once we add other related language features. Specifically, I think we should explore (whether we adopt it or not) #1974 and any other things that fundamentally impact tho parameterization of functions that we can, and then revisit this to get a more cohesive syntax across all of those.

For now, I'm going to mark this as deferred until #1974 gets explored, and then we can revisit it.

h3har commented 2 years ago

There is precedent in Julia for defining type parameters after they're used with the where keyword, as opposed to just constraining parameters that were already defined (like in Rust), e.g., see here and here.

chandlerc commented 2 years ago

There is precedent in Julia for defining type parameters after they're used with the where keyword, as opposed to just constraining parameters that were already defined (like in Rust), e.g., see here and here.

Understood, but I think this kind of forward reference within a single declaration would be especially surprising in the context of the rest of Carbon's syntax.