To me Angle is a unit with two common representations: radians and degrees. It's not an enum because it doesn't have two values, it has one value that you can view in two ways.
Therefore I would make an Angle struct, something like: //: Angle struct instead of angle enum import Foundation struct Angle { static let d2R = Double.pi / 180 static let r2D = 180 / Double.pi private var degs: Double var degrees: Double { return degs } var radians: Double { return degs * Angle.d2R } init(degrees: Double = 0) { degs = degrees.truncatingRemainder(dividingBy: 180) } init(radians: Double) { self.init(degrees: radians * Angle.r2D) } } extension Angle: Hashable { var hashValue: Int { return degs.hashValue } static func ==(lhs: Angle, rhs: Angle) -> Bool { return lhs.degs == rhs.degs } } extension Angle/*: FloatingPoint*/ { static func +(lhs: Angle, rhs: Angle) -> Angle { return Angle(degrees: lhs.degs + rhs.degs) } static func +=(lhs: inout Angle, rhs: Angle) { lhs.degs += rhs.degs lhs.degs = lhs.degs.truncatingRemainder(dividingBy: 180) } // Rest of FloatingPoint ... } // Trig extension Angle { var sin: Double { return Foundation.sin(radians) // Need to qualify name to stop name clash } // Other trig } let a = Angle(degrees: 90) // 90 a.radians // pi / 2 a.sin // 1 let b = Angle(radians: 3) // Almost pi b.degrees // 171.9 let c = a + b // Wraps over 180 degrees c.degrees // 81.9 c == b // false c.hashValue // 463... let d = Angle(degrees: -90) // -90 d.radians // -pi / 2 var e = Angle(radians: -3) // Almost -pi e.degrees // -171.9 e += d // Wraps over -180 degrees e.degrees // -81.9 -- Howard. On 19 June 2017 at 13:32, David Sweeris via swift-users < swift-users@swift.org> wrote: > > On Jun 18, 2017, at 19:30, Nevin Brackett-Rozinsky via swift-users < > swift-users@swift.org> wrote: > > Is there a way to restrict the associated values of an enum? For example, > suppose I have this type: > > enum Angle { > case radians(Double) > case degrees(Double) > } > > I want to ensure that the radians values is always in [0, 2π) and the > degrees values is always in [0, 360). Ideally I would like to write an > initializer which is called when the user writes eg. “let x: Angle = > .degrees(-45)” and contains the logic to wrap the provided value into the > allowed range (in this case by adding a multiple of 360). > > I don’t see a way to do it. Is this possible? > > The closest I’ve found is to create auxiliary types such as > > struct Degree { … } > struct Radian { … } > > and give them appropriate initializers, then use them for the associated > values. However that is undesirable because it adds an extra level of depth > to get at the actual numeric values. > > Is there a better way? > > > Not off the top of my head, at least not without changing the syntax. > > You could add two inits, with different argument labels, and not directly > set the case: “let x = Angle(degrees: -45)” > > You could add "public var radians: Double { get {...} set {...} }" (and > again for "degrees") to `Angle`. The getter would need to switch on self > to figure out if you need to convert between the two (like if someone said > ".radians(2).degrees"): “var x = Angle.radians(0); x.degrees = -45" > > Alternately, you could add "subscript() -> Double" and switch on self in > both the setter and the getter to figure out if you should be wrapping > at 2π or 360 and to do any conversions: “var x: Angle = .radians(0); x[] = > -45" > > Hope that helps > - Dave Sweeris > > _______________________________________________ > swift-users mailing list > swift-users@swift.org > https://lists.swift.org/mailman/listinfo/swift-users > >
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users