1

Wanted to toy with adding some sugar in Swift3. Basically, I wanted to be able to do something like:

let randomAdjust = (-10...10).random

To do that, I decided I would need to extend ClosedRange. But then found it would probably be even better for my case, I really just plan on doing Int's for now, to use CountableClosedRange. My latest of multiple attempts looked like:

extension CountableClosedRange where Bound == Int {
    var random:Int {
        return Int(arc4random_uniform(UInt32(self.count) + 1)) + self.lowerBound
    }
}

But the playground complains:

error: same-type requirement makes generic parameter 'Bound' non-generic
extension CountableClosedRange where Bound == Int {

I don't even know what it's telling me there.

Travis Griggs
  • 21,522
  • 19
  • 91
  • 167
  • You mean like this? http://stackoverflow.com/a/40810305/341994 – matt Jan 15 '17 at 02:35
  • http://stackoverflow.com/questions/34712453/random-number-x-amount-till-x-amount-swift/34712601?s=1|0.2659#34712601 – Leo Dabus Jan 15 '17 at 02:35
  • So what question do you want answered? I've shown you how to make a range `random` function; does that satisfy you or is the real goal to have me talk about the "I don't even know what it's telling me there" part? – matt Jan 15 '17 at 02:37
  • 1
    I think the second. I continually get really frustrated trying to extend Protocols and even more Generics in Swift. So yes, I'm curious why I can't constrain Bound to Int there. Because the light bulb just hasn't lit for me yet. I like your more generic solution over in the other answer better. But it frustrates me that I couldn't even figure out how to write a poorer one. :/ – Travis Griggs Jan 15 '17 at 02:59
  • 2
    Note that [concrete same-type requirements](https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#concrete-same-type-requirements) will be supported in Swift 3.1. – Hamish Jan 15 '17 at 10:42
  • @TravisGriggs If you do not say `@matt` in your reply to me, I can't "hear" you speaking. — Okay, I've written a little essay as an answer. – matt Jan 15 '17 at 17:32
  • @Hamish, any idea when Swift 3.1 will hit a version of XCode? – Travis Griggs Jan 17 '17 at 19:30
  • @TravisGriggs It's intended to be released "spring of 2017" – https://swift.org/blog/swift-3-1-release-process/. Yesterday (Jan 16th) was the cut-off point for changes to be made, we're now in the "bake" period. So the release date is whenever they're finished "baking". – Hamish Jan 17 '17 at 19:34

2 Answers2

9

The way this roadblock is commonly encountered is when attempting to extend Array. This is legal:

extension Array where Element : Comparable {
}

But this is illegal:

extension Array where Element == Int {
}

The compiler complains:

Same-type requirement makes generic parameter 'Element' non-generic

The problem is the use of == here in combination with Array's parameterized type Element, because Array is a generic struct.

One workaround with Array is to rise up the hierarchy of Array's inheritance to reach something that is not a generic struct:

extension Sequence where Iterator.Element == Int {
}

That's legal because Sequence and Iterator are generic protocols.

Another solution, though, is to rise up the hierarchy from the target type, namely Int. If we can find a protocol to which Int conforms, then we can use the : operator instead of ==. Well, there is one:

extension CountableClosedRange where Bound : Integer {
}

That's the real difference between our two attempts to implement random on a range. The reason your attempt hits a roadblock and mine doesn't is that you are using == whereas I am using :. I can do that because there's a protocol (FloatingPoint) to which Double conforms.

But, as you've been told, with luck all this trickery will soon be a thing of the past.

Community
  • 1
  • 1
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • That example is discussed at the end of this section of my book: http://www.apeth.com/swiftBook/ch04.html#_extending_generics – matt Jan 15 '17 at 17:17
  • 8
    And `extension Array where Element == Int` is now legal in Swift 3.1, available with Xcode 8.3 beta :) – Hamish Jan 25 '17 at 15:25
  • @Hamish at last! Thx for the heads-up. – matt Jan 25 '17 at 15:27
1

In Swift 4, what you are attempting is now completely supported. Hooray!

extension Stack where Element: Equatable {
    func isTop(_ item: Element) -> Bool {
        guard let topItem = items.last else {
            return false
        }
        return topItem == item
    }
}

Example from Swift docs: https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID553

Ky -
  • 30,724
  • 51
  • 192
  • 308