Combined SE-0366 (third review) and SE-0377 (second review): rename `take`/`taking` to `consume`/`consuming`

I find myself torn about the use of the imperative form for the parameter modifiers. Parameter modifiers are, like attributes, generally adjectival. We don't really keep to the pretense that a method declaration needs to "read like a sentence", but there is an argument for consistency between features.

For example, in the current proposal, a consumed parameter is written like this in the function declaration:

func collect(all widgets: consume [Widget])

Types usually read as descriptions of the parameter, but we wouldn't say that this is a "consume array of widgets", we'd say that it's a "consumed array of widgets". So that would argue for this:

func collect(all widgets: consumed [Widget])

Of course, that requires us to claim consumed and borrowed as keywords and use different keywords in different places based roughly on the rules of English grammar. That might be natural for programmers who are fluent in English, but it could be an obstacle for other people. On the other hand, we're already doing this elsewhere with consume vs. consuming.

An alternative would be to use the gerund for parameters, just like we do for methods:

func collect(all widgets: consuming [Widget])

This has the great merit of underlining the connection between these two placements, since the method modifier ultimately just behaves like a parameter modifier on self. And there's precedent for using gerunds here from @escaping. But it doesn't quite read right to me given the role of the ownership modifier. A parameter type is usually something that you ought to be able to read as a noun phrase that describes the argument value. "Consuming" doesn't describe the argument: it describes the relationship between the function and the argument.

( I know that some people have also argued against using the same keyword in these two places because we might want to be able to use both modifiers on functions simultaneously, in order to e.g. express the ownership relationship of first-class function values to their captured context (a sometimes important property in other languages, like Rust and C++). I don't think this is a very convincing argument, mostly because it would be a terrible idea to use such similar spellings for these different ideas — it directly invites confusion in both reading and writing code. If we find ourselves needing spellings for these properties on a function type, we probably ought to use names like @calledOnce (the effective behavior of a function that consumes its context) and @calledSequentially (the effective behavior of a function that requires a mutable reference to its context). )

I think this readability problem could potentially be resolved by moving the ownership modifier to the beginning of the clause. So you would write:

func collect(consuming all widgets: [Widget])

Of course, that would then be inconsistent with the placement of inout, which seems unfortunate in its own way. And I don't know what it would mean in function value types.

In favor of the current proposal, there's certainly an argument that we can side-step all this by just arbitrarily accepting the use of the imperative even if it's not totally consistent. Programmers will, of course, just learn whatever rule the language ends up specifying; no spelling is perfect, and inconsistency is a given.

Anyhow, I don't have a firm conclusion right now, but I wanted to put this out as food for thought.

23 Likes