Thanks for ccing me!
The core team didn't actually express an opinion about the enum nature of Change
(and at the time I wasn't aware of any history), but there is some backstory here.
I've been working on this proposal for about 4 years, and Change
was originally coded as an enum because those first versions of the proposal encoded cases that had wildly different associated values. One early version looked like:
enum Change {
case remove(at: Int)
case insert(element: ChangeElement, at: Int)
case move(from: Int, to: Int)
}
This version had a number of major issues that the proposal (and discussion) goes into more deeply, but to summarize: reverting a diff requires remove
be able to encode elements, and move
makes it impossible to safely apply a diff with a 1-pass enumeration of its changes.
That's all history, but I think it still makes sense to use associated values for Change
because, despite their matching types, offsets are not directly interchangeable between instances of insert
and remove
. To crib from a related conversation in the proposal thread:
In this way, insert
and remove
behave like different (but extremely related) types.
That leaves element
as a truly shared value, and Change
could have been more purely represented with a type like:
public enum Change {
public enum Type {
case insert(offset: Int, associatedWith: Int?)
case remove(offset: Int, associatedWith: Int?)
}
public let type: Type
public let element: ChangeElement
}
…but that's also pretty cumbersome to deal with, and is no better at serving your examples.
That all said, I am very sympathetic to the ergonomic issues and don't consider the API to be finished. The curse of writing a new API is that you can't always predict how it will be used (assuming it gets used at all ), so my main goal for SE-0240 was for the idea of diffing to be incorporated into the standard library in a distilled form that reserved the most flexibility for future improvements.
That totally includes exposing the (currently internal) convenience accessors, and between the standard library and your example here I think there's a strong argument for exposing an offset
convenience accessor in the future.