Tchelyzt - 8 months ago 21

Swift Question

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

`struct MutableAngle {`

var degrees : CGFloat

var radians : CGFloat {

return degrees * CGFloat(M_PI) / 180.0

}

init(inRadians : CGFloat) {

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`

angle.radians = 0.75

Here's another version of the structure:

`struct ImmutableAngle {`

let degrees : CGFloat

let radians : CGFloat

init(inRadians : CGFloat) {

radians = inRadians

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

let radians : Float

init(inRadians : Float ) {

radians = inRadians

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 // returns 0.7853982

// 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 = Angle(inRadians: 0.9)

alpha.radians // returns 0.7853982

alpha.degrees // returns 45

Answer

Two things here:

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`

.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
var radians : CGFloat {
get {
return degrees * CGFloat(M_PI) / 180.0
}
set {
degrees = newValue * 180.0 / CGFloat(M_PI)
}
}
init(inRadians : CGFloat) {
radians = inRadians
}
init(inDegrees : CGFloat) {
degrees = inDegrees
}
}
```

Useage:

```
// immutable
let angle = Angle(inDegrees: 180)
println(angle.radians)
// next line gives an error: can't assign to an immutable instance
angle.radians = angle.radians * 2
// mutable copy
var mutableAngle = angle
mutableAngle.degrees = 10
println(mutableAngle.radians)
// 0.1745...
mutableAngle.radians = CGFloat(M_PI)
println(mutableAngle.degrees)
// 180.0
```