[swift-users] Restricting associated values

Howard Lovatt howard.lovatt at gmail.com
Mon Jun 19 00:33:00 CDT 2017


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 at swift.org> wrote:

>
> On Jun 18, 2017, at 19:30, Nevin Brackett-Rozinsky via swift-users <
> swift-users at 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 at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170619/d2ba98fa/attachment.html>


More information about the swift-users mailing list