SE-0366: Move Function + "Use After Move" Diagnostic

I'm broadly +0.5 on this proposal—I support the addition of the move functionality at a high level but I remain apprehensive about a couple items that I raised in the pitch: namely, move(_:) as a function specifically and the lack of @discardableResult and/or drop.


The proposal introduces move as the following:

The move function consumes a movable binding, which is either an unescaped local let, unescaped local var, or function argument, with no property wrappers or get/set/read/modify/etc. accessors applied.

but IMO this is glossed over far too quickly—the concept of a "function which consumes a movable binding" (or indeed, any binding at all) is an entirely new concept, and isn't even representable in Swift today. The purported signature of the move(_:) function is a bit of a fiction. This is discussed and justified in Alternatives considered:

Declaring move as a function also minimizes the potential impact to the language syntax. We've introduced new contextual keywords without breaking compatibility before, like some and any for types. But to do so, we've had to impose constraints on their use, such as not allowing the constraints modified by some or any to be parenthesized to avoid the result looking like a function call. Although that would be acceptable for move given its current constraints, it might be premature to assume we won't expand the capabilities of move to include more expression forms.

AFAICT, though, this really only rebuts the proposed spelling of move x and not the other alternatives discussed just above such as #move(x) or @move x. In a vacuum it strikes me as equally premature to assume that move will expand to include more expression forms—the expansions discussed in Future directions still only really cover expansions of the potential bindings we could apply this function to.

As written the proposal doesn't convince me that move(_:) will ever be able to be "just another function"—not even the Ownership roadmap lays out such a scheme. If it were the plan of record that we'd be adding ownership features until move(_:) could be a function that anyone could write, I'd be a lot more on board with this direction, but since that's not the case I can't really get past the feeling that move-as-a-function isn't appropriate for Swift. There are too many limitations and special cases for not enough gain, IMO.

It's not really enough to hinder my overall support for the proposal, but I think that in its current form it will become a part of the language that we will forever have to caveat as "yes, I know it looks like a function but it's better not to think of move(_:) like a Swift function at all because X, Y, Z."


My second objection is less pressing since it could be rectified in a backwards-compatible manner, but I still think it would be nice to address as part of the initial proposal.

I also want to reiterate my thoughts on the lack of @discardableResult in this proposal, which is discussed as part of the rejection of the drop function:

We could also introduce a separate drop function like languages like Rust does that doesn't have a result like move does. We decided not to go with this since in Swift the idiomatic way to throw away a value is to assign to _ implying that the idiomatic way to write drop would be:

_ = move(x)

suggesting adding an additional API would not be idiomatic. We do not propose making move use the @discardableResult attribute, so that this kind of standalone drop is syntactically explicit in client code.

This reasoning still strikes me as somewhat backwards (in the formal sense). The way I see it is that using @discardableResult is the idiomatic way to design an API for which one of the expected uses is to discard the result. If that's the case for move(_:) then we should have move(_:) be tagged as @discardableResult. If we're worried that a bare move(x) is somehow not explicit enough (see below), that's justification for a drop function.

The idiomatic way to throw a value away is to assign to _ only in cases where the API designer does not consider discarding the result a 'supported' use case of the API—it doesn't make sense to me to design an API where we 'support` the drop functionality by forcing users to use discard assignment.

I also have this lingering related question from the pitch:

23 Likes