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

David Hart david at hartbit.com
Sun Feb 21 02:45:12 CST 2016


I’ve read the D documentation, I’ve used similar syntax in Ruby, and I agree that something along the same lines could be really expressive. I agree at least that the current Swift syntax for your example operations is much more verbose and surprising than should be.

> On 21 Feb 2016, at 01:41, Daniel Duan via swift-evolution <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.
> 2. negative index imposes runtime overhead
> 3. negative index masks fencepost errors (`foo(m-n)` supprises if you assume
>   m > n)
> 
> 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)
> //   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
> 
> 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



More information about the swift-evolution mailing list