I’m generally in favor of this and can already think of a few specific locations where this would improve performance in a meaningful way (when coupled with take expressions), even without any further language changes. Also very excited about the general progress towards move-only types.
Inside of a function or closure body, take parameters may be mutated, as can the self parameter of a taking func method.
I feel like this isn’t necessarily justified; while it is just as reasonable to mutate a take parameter as a local var, I don’t think it makes sense for that to be the default. With locals we still encourage let over var, and take doesn’t imply “mutation” to me. Certainly the implicit uses of the take convention today aren’t about mutating the value; they’re about storing it. Similarly, the use case I have in mind is purely about allowing the parameter to be destroyed sooner, avoiding having to wait for a deep stack to return.
I suppose you can always convert from one form to another by takeing into a local, but I don’t think take should imply mutability like var and inout do. I’d rather see a (separate) proposal to revert SE-0003 and revive var on parameters if we think this is interesting, noting that SE-0031 moved inout to the “type” side of the parameter declaration since SE-0003 was reviewed.
take cannot be applied to parameters of nonescaping closure type, which by their nature are always borrowed
The full form of a non-optional take closure parameter would thus be callback: take @escaping () -> Void, which is pretty verbose. (Or is it @escaping take () -> Void?) Given that escaping pretty much implies that a copy will be made anyway, does it make sense for take to imply @escaping, as inout already does today? That still leaves the occasional borrow @escaping () -> Void for where an escaping closure parameter might normally be taken, but that seems pretty rare to me; the main place where I could see it being useful is if the closure is only escaped some of the time.
On the implementation side: are non-escaping closure parameters passed borrow or take to initializers today? I would hope borrow even though the usual convention for initializer parameters is take, for the reasons discussed in this proposal, but if not this could be a good opportunity to fix some conventions (where not ABI-breaking).
Additionally, I remember the first implementation of __owned and __shared affecting a function’s mangled name even if the convention matches the implicit default for that parameter. Does that behavior extend to take and borrow, and if not…I guess there’ll be a special opt-out or shim for the stdlib, to use the explicit mangling where an implicit one would have done?
Again, very excited about all this! Thank you Michael, Joe, and everyone working on this.