[swift-evolution] Proposal: Python's indexing and slicing
kevin at sb.org
Mon Dec 21 21:47:48 CST 2015
On Mon, Dec 21, 2015, at 07:29 PM, Dave Abrahams wrote:
>>> Even if we need separate symbols for “start” and “end” (e.g. using
>>> “$” for both might just be too confusing for people in the end, even
>>> if it works otherwise), I still think a generalized form that allows
>>> ranges to be used everywhere for slicing is going to be much easier
>>> to understand than this hodgepodge of words we use today.
>> I'm tempted to say that if we do this, we should use two different
>> sigils, and more importantly we should not use + and - but instead
>> use methods on the sigils like advancedBy(), as if the sigils were
>> literally placeholders for the start/end index. That way we won't
>> write code that looks O(1) when it's not. For example:
>> Although we'd need to revisit the names a little, because $.advancedBy(-
>> 3) is a bit odd when we know that $ can't ever take a non-negative
>> number for that.
>> Or maybe we should just use $ instead as a token that means "the
>> collection being indexed", so you'd actually say something like
> I really like that direction, but I don’t think it does enough to
> solve the ease-of-use problem; I still think the result looks and
> feels horrible compared to Python for the constituencies
> mentioned above.
> I briefly implemented this syntax, that was intended to suggest
> repeated incrementation:
> col.startIndex++3 // col.startIndex.advancedBy(3)
> I don’t think that is viable, especially now that we’ve dropped “++”
> and “--“. But this syntax
> begins to be interesting for some definition of ⛄️.
I could definitely see this working given an appropriate operator. I'm
opposed to + because I think that the notion of addition is strongly
tied to O(1) behavior, and the precedent in Swift is for addition to
trap if it goes out of bounds instead of to be saturating (or however
you want to describe that behavior).
There is a potential concern here though which is that some operations
make sense as "saturating" slices (e.g. the offsets are trimmed to be
in-bounds) and some would likely want to trap for out of bounds. This
would be the difference between the advancedBy(_:) and
advancedBy(_:limit:) methods. This is one reason why I suggested using $
merely as a stand-in for the collection, so the existing behavior around
advancedBy(_:) vs advancedBy(_:limit:) would apply. More generally, any
slicing operation that's the equivalent of prefix(), dropFirst(), or
dropLast() would likely want the "saturating" behavior, but any slicing
operation that's working with explicit offsets and merely wants to make
it more concise would want to trap if the offsets go out of bounds. This
could be represented as two different operators (if the trapping
operator is ⛄️ perhaps the "saturating" one could even be &⛄️, just as
&+ is the non-trapping version of +).
As for operator choice, my first idea was to use ~> (and I know it's
already taken, but that's an internal implementation detail and could be
changed), but when I tried writing out the 3..<5 example it looks weird
to have > be in the operator that's used with ..<, because that becomes
col[$.start~>3..<$.start~>5]. So I think something else is more
appropriate. Heck, the ++ suggestion you offered has promise, especially
now that we've dropped ++ and --.
On another note, I'm tempted to say that we should use $start and $end
instead of $.start and $.end. The compiler doesn't currently allow this,
because it expects a number after the $, but I see no reason why we
can't relax that rule and allow $start to be a valid token. The benefit
of this approach is it frees up $ to be used by third-party code (such
as in the older thread about rebinding `self` for DSLs where I suggested
that a block-based API can use $ as the parameter name so code would say
something like `$.expect(foo).to(.equal(bar))`).
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the swift-evolution