[swift-evolution] [Discussion][Expericment] D-like slicing syntax

Dave Abrahams dabrahams at apple.com
Sun Feb 21 05:33:53 CST 2016


on Sat Feb 20 2016, Daniel Duan <swift-evolution at swift.org> wrote:

> Hi all,
>
> A while ago there's a thread on adding Python's slicing syntax here:
> http://thread.gmane.org/gmane.comp.lang.swift.evolution/124/focus=261
>
> From it, a brief summary of the issues in Python's slicing syntax:
>
> 1. light syntax may suggest O(1) operation complexity to some.

Slicing is always O(1) in swift, so that's a desirable property.

> 2. negative index imposes runtime overhead
> 3. negative index masks fencepost errors (`foo(m-n)` supprises if you assume
>    m > n)

Yes.

> D's slicing syntax (https://dlang.org/d-array-article.html) was brought up as
> an alternative. It does a better job in suggesting "unusual" operation (if you
> treat subscripting with an index as normal). I attached a rudimentary
> implementation of it at the end. It's in not way aimed at being complete or
> ending up in stdlib. Hopefully, being able to play with it will generate more
> discussion on this topic :)
>
> // (if you prefer a gist: https://gist.github.com/dduan/5c54df865fdd7b6b7548)
> //
> // Incomplete:
> //   '%' replaces the more ideal '$' (the latter can't be in name of
> // operator)

You don't need it to be an operator; you can just define a var called $
and create operator overloads for + and - that let you build the
expressions you want.

> 
> // where a open ended range is in the design, `nil` is used its place
> // force casting between Index.Distance and 'Int' 
> // only on CollectionType, but a version for string is not hard to add

Why not just make

    x[..<$-2]

work?  You can create unary overloads for ..<


> public struct Offset { let value: Int }
>
> prefix operator %+ {}
> prefix operator %- {}
>
> prefix func %+(offset: Int) -> Offset {
>     return Offset(value: offset)
> }
> prefix func %-(offset: Int) -> Offset {
>     return Offset(value: -offset)
> }
>
> internal func normalize(start: Int?, end: Int?, total: Int) -> (Int, Int) {
>     var actualStart = start ?? 0
>     var actualEnd = end ?? total
>     actualStart = actualStart < 0 ? total + actualStart : actualStart
>     actualEnd = actualEnd < 0 ? total + actualEnd : actualEnd
> //  uncomment the following for a much more forgiving index behavior
> //  actualStart = actualStart < 0 ? 0 : actualStart
> //  actualEnd = actualEnd < 0 ? 0 : actualEnd
> //  let safeEnd = min(actualEnd, total)
> //  return (min(actualStart, safeEnd), safeEnd)
>     return (actualStart, actualEnd)
> }
>
> extension CollectionType {
>     public subscript(start:Offset?, end:Offset?) -> Self.SubSequence {
>         let (safeStart, safeEnd) = normalize(
>             start?.value, end: end?.value, total: self.count as! Int)
>         let safeStartIndex = startIndex.advancedBy(
>             safeStart as! Self.Index.Distance)
>         let safeEndIndex = startIndex.advancedBy(
>             safeEnd as! Self.Index.Distance)
>         return self[safeStartIndex..<safeEndIndex]
>     }
>
>     public subscript(index: Offset) -> Self.Generator.Element {
>         let (safeStart, _) = normalize(
>             index.value, end: 0, total: self.count as! Int)
>         return self[startIndex.advancedBy(safeStart as! Self.Index.Distance)]
>     }
> }
>
> let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>
>             // equavelent in Swift            Python     Result
> s[%+2]      // s[s.startIndex.advancedBy(2)]  s[2]       2
> s[%-2]      // s[s.endIndex.advancedBy(-2)]   s[-2]      8
> s[%+2, %-3] // s.dropFirst(2).dropLast(3)     s[2:-2]    [2, 3, 4, 5, 6]
> s[%-5, nil] // s.dropFirst(s.count - 5)       s[-5:]     [5, 6, 7, 8, 9]
> s[nil, %-8] // s.dropLast(8)                  s[:-8]     [0, 1]
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-- 
-Dave



More information about the swift-evolution mailing list