Search code examples
swiftrangeoperatorsoperator-precedenceinfix-operator

Custom Range Operators - Swift 4.1


Custom Range Operators

Swift 4.1, Xcode 9.3

I am looking to make two custom range operators: <.., <.<


1. <..

  • This operator will be sort of the inverse of the ..< range operator.

My Attempt:

infix operator <.. : RangeFormationPrecedence

public func <.. (lhs: Int, rhs: Int) -> Range {
    return lhs - 1 ... rhs
}

Errors:

1. Custom Range Operator Error

Note: I also get about an additional 22 compile time errors surrounding the actual declaration of the custom operator (<..) itself.

Ideal Usage:

for i in 1<..9 {
    print(i, terminator: " ")
}

// Prints "0 1 2 3 4 5 6 7 8 9"

2. <.<

  • I want to make sort of a combination of my previous custom range operator. <.. and ..<

My Attempt:

infix operator <.< : RangeFormationPrecedence

public func <.< (lhs: Int, rhs: Int) -> Range {
    return lhs - 1 ..< rhs
}

Errors:

2. Custom Range Operator Error

Note: I also get about an additional 22 compile time errors surrounding the actual declaration of the custom operator (<.<) itself.

Ideal Usage:

for i in 1<.<10 {
    print(i, terminator: " ")
}

// Prints "0 1 2 3 4 5 6 7 8 9"

How can I accomplish this?

Also, what type of Range should I be returning?

Lastly, are there any preconditions that need to be added to the custom range operators themselves to ensure safety?


Update

I decided to create two operators (1x postfix, 1x infix) to accomplish one of these goals:

postfix operator <

public postfix func < <T: Numeric>(n: T) -> T { return n - 1 }


infix operator .< : RangeFormationPrecedence

public func .< <T: Numeric>(lhs: T, rhs: T) -> CountableRange<T> {
    return lhs ..< rhs
}

Then I can do:

for i in 1<.<10 {
    print(I, terminator: " ")
}

//Prints "0 1 2 3 4 5 6 7 8 9"

Caveat: I cannot have a space between the numbers and the operators (i.e. 1 <.< 10)



Solution

  • <.. and <.< are not valid identifiers for operators. You'll find the details in Operators in the Swift language reference.

    Mimicking the declaration of the existing

    extension Strideable where Self.Stride : SignedInteger {
        public static func ... (minimum: Self, maximum: Self) -> CountableClosedRange<Self>
    }
    

    operator, your first custom operator can be implemented as

    infix operator <!! : RangeFormationPrecedence
    
    extension Strideable where Self.Stride : SignedInteger {
        public static func <!! (minimum: Self, maximum: Self) -> CountableClosedRange<Self> {
            return minimum.advanced(by: -1) ... maximum
        }
    }
    

    Example:

    for i in 1<!!9 { print(i, terminator: " ") }
    // 0 1 2 3 4 5 6 7 8 9
    

    The second operator can be implemented in a similar fashion, using CountableRange instead of CountableClosedRange.