# Ranges for enum and struct types

by @ralfebert · updated January 20, 2022

Swift has a syntax for ranges of values:

```0...5    // represents [0, 1, 2, 3, 4, 5]
0..<5    // represents [0, 1, 2, 3, 4]
(0...5).contains(3)   // true
(0...5).forEach { number in print(number) }
```

By default this is supported for numeric types. But can this be enabled for enums and structs as well? For example, in one application I have an enum type to represent musical notes and intervals:

```public enum NoteLetter {
case C, D, E, F, G, A, B
}

public struct Interval {
var semitones : Int

public static let unison = Interval(semitones: 0)
public static let minorSecond = Interval(semitones: 1), majorSecond = Interval(semitones: 2)
public static let minorThird = Interval(semitones: 3), majorThird = Interval(semitones: 4)
public static let fourth = Interval(semitones: 5)
public static let tritone = Interval(semitones: 6)
public static let fifth = Interval(semitones: 7)
public static let minorSixth = Interval(semitones: 8), majorSixth = Interval(semitones: 9)
public static let minorSeventh = Interval(semitones: 10), majorSeventh = Interval(semitones: 11)
public static let octave = Interval(semitones: 12)
}
```

It would be nice to be able to define ranges based on this type like this:

```NoteLetter.C..<NoteLetter.F
Interval.fifth..<Interval.octave
```

By default, this will give an error:

• Referencing operator function '..<' on 'Comparable' requires that 'NoteLetter' conform to 'Comparable'
• Referencing operator function '..<' on 'Comparable' requires that 'Interval' conform to 'Comparable'

To be used as a range, the type needs to implement the Strideable protocol that defines how to measure the distance between two values and how to go from one value to antother one by distance:

```public enum NoteLetter: Int, Strideable {

case C, D, E, F, G, A, B

public func distance(to other: NoteLetter) -> NoteLetter.Stride {
return Stride(other.rawValue) - Stride(self.rawValue)
}

public func advanced(by n: NoteLetter.Stride) -> NoteLetter {
return NoteLetter(rawValue: numericCast(Stride(self.rawValue) + n))!
}

public typealias Stride = Int
}
```

The same is possible for structs:

```public struct Interval : Strideable {
var semitones : Int

public static let unison = Interval(semitones: 0)
public static let minorSecond = Interval(semitones: 1), majorSecond = Interval(semitones: 2)
public static let minorThird = Interval(semitones: 3), majorThird = Interval(semitones: 4)
public static let fourth = Interval(semitones: 5)
public static let tritone = Interval(semitones: 6)
public static let fifth = Interval(semitones: 7)
public static let minorSixth = Interval(semitones: 8), majorSixth = Interval(semitones: 9)
public static let minorSeventh = Interval(semitones: 10), majorSeventh = Interval(semitones: 11)
public static let octave = Interval(semitones: 12)

public func distance(to other: Interval) -> Interval.Stride {
return Stride(other.semitones) - Stride(self.semitones)
}

public func advanced(by n: Interval.Stride) -> Interval {
return Interval(semitones: numericCast(Stride(self.semitones) + n))
}

public typealias Stride = Int

}
```