Syntactic sugar for assignment precondition: x = a -> b

One would write x = a -> b to make x change its value from a to b. This is syntactic sugar for:

precondition( x == a )
x = b

This pattern comes up a lot when you want to increase your confidence that your code is doing what you think it should be doing.

I don't buy it, it's too cryptic from my point of view. You can easily create a simple function that does everything you want in one line and is far more readable, so -1 for me.

func change<T>(_ value: inout T, from oldValue: T, to newValue: T) {
  precondition(value == oldValue)
  value = newValue
}

// usage
change(x, from: a, to: b)
10 Likes

I agree with @DevAndArtist that this probably doesn't rise to the level of needing an operator. There's a widely-used term of art for this operation: "compare-and-swap". I would expect expect any library implementation to use a variant of that name.

(I would also expect it to not have a precondition, but return either Bool or Optional<T> indicating whether the check succeeded--and the new value in the case of an Optional--which the caller could then handle by a fatalError if they really want the precondition behavior or more likely do something else.)

The -> operator as defined above would encourage you to use this sort of assignment more frequently as it would have minimal impact on the readability of your code.

Not exactly the requested syntax, but you can do something like

struct Update<Value> {
	var from: Value
	var to: Value
}

infix operator =>

func => <Value> (lhs: Value, rhs: Value) -> Update<Value> {
	return Update(from: lhs, to: rhs)
}

struct InvalidUpdateError<Value>: Error where Value: Equatable {
	var value: Value
	var update: Update<Value>
}

infix operator != : AssignmentPrecedence

func != <Value> (lhs: inout Value, rhs: Update<Value>) throws where Value: Equatable {
	guard lhs == rhs.from else { throw InvalidUpdateError(value: lhs, update: rhs) }
	lhs = rhs.to
}

var foo: Int = 3
try foo != 3 => 4
print(foo) // 4
1 Like