Tchelyzt - 7 months ago 9
Swift Question

# Symmetry in using structures for conversion. What is best practice?

I've been playing with Swift and I encoded an obvious conversion structure:

``````struct MutableAngle {
var degrees : CGFloat
return degrees * CGFloat(M_PI) / 180.0
}

degrees = inRadians * 180.0 / CGFloat(M_PI)
}
init(inDegrees : CGFloat) {
degrees = inDegrees
}
}
``````

Now this is fine but inelegant since it doesn't treat degrees and radians symmetrically although it does give mutability. This is really a structure which should be called Degrees and which can provide radians. For instance, I can write:

``````var angle : MutableAngle
angle.degrees = 45.0
``````

but not

``````var angle : MutableAngle
``````

Here's another version of the structure:

``````struct ImmutableAngle {
let degrees : CGFloat

degrees = inRadians * 180.0 / CGFloat(M_PI)
}
init(inDegrees : CGFloat) {
degrees = inDegrees
radians = inDegrees * CGFloat(M_PI) / 180.0
}
}
``````

Switching from var to let makes it immutable and I can enforce the conversion in the constructors which I'm now obliged to use. I must write:

``````var angle = ImmutableAngle(inDegrees: 45.0)
``````

or

``````var angle : ImmutableAngle(inRadians: 0.75)
``````

So its symmetric. It also has the merit that a calculation is not required every time I want to use the radians.

Here's a final version:

``````struct Angle {
let degrees : Float

degrees = radians * Float (180 / M_PI)
}
init(inDegrees : Float ) {
degrees = inDegrees
radians = degrees * Float (M_PI / 180)
}
}
``````

Use as follows:

``````var alpha = Angle(inDegrees: 45)
alpha.degrees // returns 45

// alpha.radians = 0.9  ... is now illegal with let constants
// must use constructor ... provided alpha was defined using 'var'
// i.e. the struct itself is mutable
alpha.degrees // returns 45
``````

Two things here:

1. In Swift you don't need a separate mutable type for value types - that's handled by whoever is instantiating the type by using `let` or `var`.

2. Your `radians` computed property only has a getter - you can do what you want with both a setter and a getter.

My implementation:

``````struct Angle {
var degrees : CGFloat = 0
get {
return degrees * CGFloat(M_PI) / 180.0
}
set {
degrees = newValue * 180.0 / CGFloat(M_PI)
}
}

}
init(inDegrees : CGFloat) {
degrees = inDegrees
}
}
``````

Useage:

``````// immutable
let angle = Angle(inDegrees: 180)