> On 19. Jun 2017, at 04: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?
>
> Nevin
> _______________________________________________
> swift-users mailing list
> swift-users@swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
> <https://lists.swift.org/mailman/listinfo/swift-users>
I suggested a type like this when Xiaodi announced his maths library, but a
more efficient implementation would look like this:
public struct Angle<T: FloatingPoint> {
public let radians: T
public var degrees: T {
return (radians / .pi) * 180
}
public static func radians(_ rads: T) -> Angle {
return Angle(radians: rads)
}
public static func degrees(_ degs: T) -> Angle {
return Angle(radians: (degs / 180) * .pi)
}
}
Floating-points don’t have extra inhabitants, so the enum representation would
occupy { float size + 1 byte } of storage, with the extra byte marking which
enum case you have.
A better approach is to store a single, normalised value (in this case, the
‘radians' value), and to provide initialisers which validate and normalise
those input values. In your case, you wrap them to an allowed range.
I think the best-practice advice in this situation would be to consider
switching: will anybody need to switch over the cases of your enum? In this
case, no - Angle<T> is just a wrapper which statically verifies that the angle
is in the expected “notation”; You want to put an angle of either notation in,
and grab the same angle out in another notation. The underlying stored notation
is an implementation detail, so a struct is better.
- Karl
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users