[swift-evolution] [Draft] Rationalizing Sequence end-operation names

Patrick Smith pgwsmith at gmail.com
Tue Jun 28 08:53:59 CDT 2016


Hi Brent,

Will an IncompleteRange always be able to be translated into the same concrete Range? i.e., the missing bound is just a stand in for startIndex or endIndex right? It seems unfortunate to have this throw away value that is only used as an intermediary. Especially when Collection already has an intermediary in the form of Index.


What if instead, you ask a collection for a prefix or suffix range from an index?

c.indexes(preceding: Index, inclusive: Bool)
c.indexes(succeeding: Index, inclusive: Bool)

These then return a Range or ClosedRange. This I believe would resolve the ‘suffix’ naming issue you have highlighted here, as instead of asking for a suffix from the *collection*, you are asking the all successors of an *index*.


Then subscripts are also added to retrieve slices. The subscripts already infer the use of indexes, so there is no need to add additional words here.

c[preceding: Index, inclusive: Bool]
c[succeeding: Index, inclusive: Bool]

This is a variation of your proposed conservative index-based operation.


Also, for the removing- base operations:

c[withoutPreceding: Index, inclusive: Bool]
c[withoutSucceeding: Index, inclusive: Bool]

c.remove(preceding: Index, inclusive: Bool)
c.remove(succeeding: Index, inclusive: Bool)


I think the words ‘preceding’ and ‘succeeding’ fit in well with the concept of ‘earliest’ and ‘latest’. Note I originally tried writing without the additional ‘inclusive’ parameter until I realised succeeding would have to be inclusive for the current suffix behaviour. It appears to make the API more complicated, but it may help to be more explicit wrt index inclusiveness that simple prefix and suffix methods ignore, and also the use of indexes instead of distances (or perhaps iteration counts?).


Hope some of this is useful! (I might be completely missing the mark)

Patrick


> On 28 Jun 2016, at 9:46 PM, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
> 
> Addressing the same issue from several people:
> 
>> On Jun 23, 2016, at 11:28 AM, David Hart <david at hartbit.com> wrote:
>> 
>> I’m not a fan of the subscript solutions. They both introduce new types which seems very heavyweight for such a small use case. I’d vote for keeping the current functions.
> 
>> On Jun 23, 2016, at 10:46 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>> 
>> Ditto, not a fan of a subscript solution here. It is true that `suffix(from:)` seems weird at first, but it is literally nonsensical to interpret the single argument any other way, partly because of the mandatory argument label but mostly because a "suffix" that doesn't go to the end isn't a suffix.
> 
> 
>> On Jun 23, 2016, at 1:06 PM, Anton Zhilin via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> -1, because [separate point snipped] they match the 
>> theme you are proposing, while subscripts do not.
> 
> Superficially, `prefix(upTo:)`, `prefix(through:)` and `suffix(from:)` appear to be prefix and suffix operations, but I think that's actually a poor way to model them.
> 
> The problem is most obvious when you look at `suffix(from:)`. Imagine you have a four-element array:
> 
> 	Elements:	a	b	c	d
> 	Indices:		[0]	[1]	[2]	[3]
> 
> `prefix(2)` and `suffix(2)` will select the first and last two elements, respectively.
> 
> 	Elements:	a	b	c	d
> 	Indices:		[0]	[1]	[2]	[3]
> 	prefix(2)		^^	^^
> 	suffix(2)				^^	^^
> 
> And for a four-element array, so will `prefix(upTo:)` and `suffix(from:)`.
> 
> 	Elements:	a	b	c	d
> 	Indices:		[0]	[1]	[2]	[3]
> 	prefix(2)		^^	^^
> 	  upTo: 2		^^	^^
> 	suffix(2)				^^	^^
> 	  from: 2				^^	^^
> 
> However, if you insert an element in the middle of the array, a funny thing happens:
> 
> 	Elements:	a	b	c	e	d
> 	Indices:		[0]	[1]	[2]	[3]	[4]
> 	prefix(2)		^^	^^
> 	  upTo: 2		^^	^^
> 	suffix(2)					^^	^^
> 	  from: 2				^^	^^	^^
> 
> Unlike the other methods, adding additional elements changed the length of `suffix(from:)`'s return value. That indicates to me that it is *not* a suffix operation at all.
> 
> Now, the simplest way to resolve this is to say that `suffix(from:)` is actually misnamed; it should be `removingPrefix(upTo:)`. That will work for arrays, but not necessarily for other collections.
> 
> For instance, I've sketched a LinkedList type here: <https://gist.github.com/brentdax/20fba60dd782045faa1cfefcde298874> The important thing to note about this type is that it uses an opaque index which always points to the same node, even if you insert or remove other nodes. Thus, unlike an array, inserting or removing an element before a particular element doesn't invalidate its index. (If you're wondering, the Collection documentation doesn't seem to imply this is a forbidden design.)
> 
> Now let's build a linked list of four elements. Since this time we have non-integer indices, I'll call them i0, i1, etc.
> 
> 	Elements:	a	b	c	d
> 	Indices:		[i0]	[i1]	[i2]	[i3]
> 	prefix(2)		^^	^^
> 	  upTo: i2		^^	^^
> 	suffix(2)				^^	^^
> 	  from: i2				^^	^^
> 
> Now what happens if we insert a new element at `j`, a new index between `i0` and `i1`?
> 
> 	Elements: 	a	e	b	c	d
> 	Indices:		[i0]	[j]	[i1]	[i2]	[i3]
> 	prefix(2)		^^	^^
> 	  upTo: i2		^^	^^	^^
> 	suffix(2)					^^	^^
> 	  from: i2					^^	^^
> 
> How about that? We see the same anomalous expansion behavior, but from the start instead of the end of the linked list. We can, of course, expand both of them:
> 
> 	Elements: 	a	e	b	c	f	d
> 	Indices:		[i0]	[j]	[i1]	[i2]	[k]	[i3]
> 	prefix(2)		^^	^^
> 	  upTo: i2		^^	^^	^^
> 	suffix(2)						^^	^^
> 	  from: i2					^^	^^	^^
> 
> This is not behavior you get out of *any* of the other prefix or suffix methods. What *do* you get this behavior from? Range subscripts. `linkedList[i0..<i2]` would behave in exactly the same way this does.
> 
> That's why I say in the proposal that:
> 
>> prefix(upTo:), prefix(through:), and suffix(from:) at first appear to belong to the same family as the other prefix and suffix methods, but deeper examination reveals otherwise.
> 
> 
> These operations behave differently under mutation than the other `prefix` calls, but very similarly to other range operations. Thus, I prefer to think of them as a funny range operation, not a `prefix` or `suffix` operation.
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution



More information about the swift-evolution mailing list