Though that is better aligned with other function modifiers (such as async and throws), it's worth noting that mutating with the former syntax already exists in the language, so to do that would be a breaking change. If the first syntax even becomes so much as a warning, we may see libraries having to do this:
This would introduce inconsistency with the fact that async and throws are keywords for denoting effects and already have their own set of "rules". Both are parts of their type signatures, (Int) -> String and (Int) async -> String are different (even though they have a certain subtyping relationships), while (Int) mutates -> String does not make sense as a standalone type signature. Effectful read-only properties were introduced in SE-0310, allowing get async and get throws in property declarations. In the light of that, what would get mutates even mean?
Additionally, throws has counterparts in throw and rethrows. async has await and potentially reasync, as discussed in future directions of the corresponding proposal. I don't think mutate and remutates make sense even at a conceptual level. In this sense, taking, borrowing, and mutating are not function/property effect modifiers.
Rust’s notion of “mutable borrow” does indeed correspond to Swift’s inout. They’re slightly different (and so are the two “borrow”s) because Rust’s references are first-class values that promise a pointer representation and Swift’s are calling conventions that do not expose the representation. (For example, a borrowed Int in Swift will still be passed by value because it is a small frozen trivially-copyable struct.)
If we want a consistency argument, mutating and the new proposed keywords affect how self behaves within the function, while also changing the self the function is called on. What other modifiers on functions affect self like this? static/class, and maybe convenience as a stretch. These also appear at the start of the declaration.
(I don’t put a lot of stock in consistency here, though, cause it’s clear that “before the declaration” is the default place to put modifiers in Swift, and throws and async are the unusual ones.)
That's an interesting question. borrowing set would indeed be equivalent to nonmutating set, but we should probably keep the existing spelling working for compatibility. As you noted, __consuming is currently allowed on get and set accessors, and I would say taking and borrowing ought to be allowed as well. It doesn't really make sense to allow them on didSet or willSet since those get absorbed into the setter and modify coroutine ABI-wise, and they always follow the ownership semantics for setting a stored property of the containing type (which would be mutating for a struct or borrowing for a class).
It might be interesting to allow set to borrow or inout its newValue, but I think that doing so requires further language design to work out what that means in relation to the borrow/inout access on the base of the property being set. (Similar issues cloud our ability to put throws on set, for instance.) So I think it makes sense to explicitly subset setters out of this initial proposal. Since willSet and didSet are tied to the default assignment behavior of stored properties, I don't think that modifying the semantics of oldValue/newValue is particularly useful.
Taking is an action. Owning is a state. Taking means a transference of possession.
If an owned object can be borrowed, then an owning function is a contradiction in terms, because it explicitly cuts off this possibility: 1. by scope 2. by voiding the argument.
Actually, the term of borrowing is also not quite there. In actuality, how many borrowers have access to the same thing? How can multiple borrowers get the same thing?
Only 1. by reproduction, i.e. copy onto parameter or 2. by glimpsing into its argument in place, not moving or copying.
Only single-access borrowing should actually be considered borrowing.
(Considering that its intention is to change the value, it’s not perfect as well. You wouldn’t expect a thing you lend to return changed. The contract is usually precisely that trust is given to not change it. But at least changing it is not precluded.)
3 a musing, not even a suggestion
I myself enjoy a different analogy – that of flows. Terms like conduit, flow, tapping, filling.
One could imagine the value as a quantum of energy. Then borrowing is tapping, and mutable borrowing is switching or swapping. Or mutating.
I like the similarity of Take and Tap and how it separates itself from mutation in situ, which is the most special case and the main antagonist.
(I also like the mut of rust, as it does not only mutate, but ‘mute’ the value for the time being – not other place can have it). But it’s too poetic for the other tastes.
Whatever modifier we choose to put in (front of?) the function, I think mutating needs to match inout. If we go with a naming scheme like takes, borrows, mutates then an inout parameter should also be spelled mutate. Because as it currently stands, take is a verb, borrow will be a verb and inout will have an adjective role.