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

Daniel Duan daniel at duan.org
Sat Feb 27 22:12:20 CST 2016

```Dave Abrahams via swift-evolution <swift-evolution at ...> writes:

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

> Why not just make
>
>     x[..<\$-2]
>
> work?  You can create unary overloads for ..<

Hi Dave, I took another stab at it today. The code is in the following link as
well as end of this email:
https://gist.github.com/dduan/fcd33a09fae4640fc83c

This implementation is almost good IMO :)

struct Dollar {}

let \$ = Dollar()

struct BInt: IntegerLiteralConvertible {
let bool: Bool
let int: UInt
func relativeTo(total: Int) -> Int {
return bool ? total - Int(int) : Int(int)
}
init(_ b: Bool, _ n: UInt) {
bool = b
int = n
}
init(integerLiteral value: Int) {
bool = false
int = UInt(value)
}
}

func -(h: Dollar, d: UInt) -> BInt { return BInt(true, d) }

typealias IncompleteRange = (BInt?, BInt?)

prefix operator ..< {}
prefix func ..<(end: BInt) -> IncompleteRange {
return (nil, end)
}

postfix operator ..< {}
postfix func ..<(start: BInt) -> IncompleteRange {
return (start, nil)
}
prefix operator ... {}
prefix func ...(end: BInt) -> IncompleteRange {
return (nil, BInt(end.bool, end.int+1))
}
postfix operator ... {}
postfix func ...(start: BInt) -> IncompleteRange {
return (start, nil)
}

func ..<(start: BInt, end: BInt) -> IncompleteRange {
return (start, end)
}

func ...(start: BInt, end: BInt) -> IncompleteRange {
return (start, BInt(end.bool, end.int+1))
}

internal func normalize(range: IncompleteRange, total: Int) -> (Int, Int) {
var actualStart = range.0 == nil ? 0 : range.0!.relativeTo(total)
var actualEnd = range.1 == nil ? total : range.1!.relativeTo(total)
actualStart = actualStart < 0 ? total + actualStart : actualStart
actualEnd = actualEnd < 0 ? total + actualEnd : actualEnd
return (actualStart, actualEnd)
}

extension CollectionType {
subscript(halfRange: IncompleteRange) -> Self.SubSequence {
let (safeStart, safeEnd) = normalize(
halfRange,
total: self.count as! Int
)
safeStart as! Self.Index.Distance)
safeEnd as! Self.Index.Distance)
return self[safeStartIndex..<safeEndIndex]
}
}

let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

// all of these expression results in [6, 7, 8, 9]
s[6...]
s[(\$-4)...]
s[6..<s.count]
s[6..<\$-0]
s[\$-4...9]

```