[swift-evolution] Feature proposal: Range operator with step

Howard Lovatt howard.lovatt at gmail.com
Mon Mar 28 18:05:48 CDT 2016


You could implement Range like below. So that range[i] = first + i *
stride. This makes Range play nice with floats and other non-exact
quantities.

/// Provide the capabilities needed to impliment Range.

/// Ranges are indexed with an Int index between 0 and count - 1 inclusive
and they return start + index * stride, where start and stride are Rangees.

/// Via extensions Int and Double are Rangees.

protocol Rangee {

    /// self += rhs

    mutating func add(rhs: Self)



    /// self -= rhs

    mutating func sub(rhs: Self)



    /// self *= rhs

    mutating func mult(rhs: Self)



    /// self /= rhs

    mutating func div(rhs: Self)



    /// Converts to an Int, truncating towards 0 if necessary

    var toInt: Int { get }



    /// Convert from an int, fails if the int is not representable

    static func fromInt(i: Int) -> Self

}


// Make Int a Rangee

extension Int: Rangee {

    mutating func add(rhs: Int) { self += rhs }

    mutating func sub(rhs: Int) { self -= rhs }

    mutating func mult(rhs: Int) { self *= rhs }

    mutating func div(rhs: Int) { self /= rhs }

    var toInt: Int { return self }

    static func fromInt(i: Int) -> Int { return i }

}


// Make Double a Rangee

extension Double: Rangee {

    mutating func add(rhs: Double) { self += rhs }

    mutating func sub(rhs: Double) { self -= rhs }

    mutating func mult(rhs: Double) { self *= rhs }

    mutating func div(rhs: Double) { self /= rhs }

    var toInt: Int { return Int(trunc(self)) }

    static func fromInt(i: Int) -> Double { return Double(i) }

}


/// An immutable-array-like collection that represents a
potentially-inclusive range of Rangables such that `range[index] = first +
index * stride`, where index in an Int between 0 and count - 1.

/// `count = Int(trunc((last - first) / stride)) + 1`;

/// therefore if `(last - first) / stride` is an integer, then the range
includes last (or approximately last if underlying arithmetic type is
non-exact).

/// Name is MyRange to stop clash with Range, in practice woule be Range.

struct MyRange<R: Rangee>: CollectionType {

    let first: R

    let last: R

    let stride: R

    let count: Int

    init(first: R, last: R, stride: R) {

        self.first = first

        self.last = last

        self.stride = stride

        self.count = MyRange.index(first: first, stride: stride, of: last)
+ 1

    }

    private static func index(first first: R, stride: R, of: R) -> Int {

        var index = of

        index.sub(first)

        index.div(stride)

        return index.toInt

    }

    func index(of: R) -> Int { return MyRange.index(first: first, stride:
stride, of: of) }

    var endIndex: Int { return count }

    var startIndex: Int { return 0 }

    // Note Range not MyRange needed for subscriptable range, in practice
MyRange would be Range

    subscript(bounds: Range<Int>) -> MyRange<R> { return MyRange(first: self
[bounds.startIndex], last: self[bounds.endIndex - 1], stride: self.stride) }

    subscript(index: Int) -> R {

        guard index >= 0 else { fatalError("Index, \(index), negative") }

        guard index < count else { fatalError("Index, \(index), >= count, \(
count)") }

        var result = stride

        result.mult(R.fromInt(index))

        result.add(first)

        return result

    }

}

  -- Howard.

On 29 March 2016 at 09:35, Erica Sadun via swift-evolution <
swift-evolution at swift.org> wrote:

>
> > On Mar 28, 2016, at 3:54 PM, Dave Abrahams via swift-evolution <
> swift-evolution at swift.org> wrote:
> >
> >
> > on Mon Mar 28 2016, Erica Sadun <swift-evolution at swift.org> wrote:
> >
> >>> On Mar 28, 2016, at 3:25 PM, Dave Abrahams via swift-evolution
> >>> <swift-evolution at swift.org> wrote:
> >>>
> >>>
> >>> on Mon Mar 28 2016, Xiaodi Wu
> >>
> >>> <swift-evolution at swift.org
> >>> <mailto:swift-evolution at swift.org>>
> >>> wrote:
> >>>
> >>>> Right, Countable could refine Strideable. I'm no expert on this, but
> >>>> some cursory reading suggests that the analogous feature in C++ simply
> >>>> requires the type to have operator++ defined. Obviously, that won't
> >>>> work for Swift 3.0...
> >>>
> >>> Hmm, instead of defining a new protocol (Countable), what if we just
> use
> >>> “Strideable where Stride : Integer” as a constraint?
> >>
> >> I like a differentiation between continuous and discrete things
> >> although both can have ranges, membership, fences,
> >> and a way to stride through them
> >
> > Strideable where Stride : Integer expresses just exactly that.  Now if I
> > could only get the type-checker to cooperate...
>
> I am ridiculously excited about what you're doing there.
> Looking forward to beautiful floating point strides if for no
> other reason than I can point out how well they work for math
> in comparison to traditional for;;loops, so maybe people will
> stop burning semicolons on my lawn.
>
> What are you feelings about disjoint and invertible intervals?
> (I'll admit they currently fail the Lattner test[1], but they appeal to
> my aesthetics)
>
> -- E
>
> [1] First rule of Lattner: A language change should provide a highly
> focused
> tweak to Swift with limited impact and a measurable benefit to developers
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160329/ddab9904/attachment.html>


More information about the swift-evolution mailing list