swift2 - Swift binary operator for protocols that returns the receiver type (which conforms to the Protocol) -
for friday fun, wanted model angles in interchangable formats. i'm not sure if i've done in swift idiomatic way, i'm learning. have angle
protocol, , 3 different struct types (radians, degrees, , rotations) conform angle protocol. i'd able add/subtract them, trick is, want lhs
argument dictate return type. example:
degrees(180) + rotations(0.25) --> degrees(270)
or
rotations(0.25) + radians(m_pi) -> rotations(0.75)
what hoping like
func + (lhs:angle, rhs:angle) -> angle { return lhs.dynamictype(rawradians: lhs.rawradians + rhs.rawradians) }
the angle
protocol requires var rawradians:cgfloat { }
init(rawradians:cgfloat)
i smalltalk-esque double dispatch approach, think there more swift appropriate approach (especially 1 requires less code, double dispatch requires lot of boilerplate code).
you need generic addition:
func +<a: angle>(lhs: a, rhs: angle) -> { return a(rawradians: lhs.rawradians + rhs.rawradians) }
this way addition return whatever type on lhs.
generally speaking, if you're using dynamictype
, you're fighting swift. swift relies more on generics , protocols (i.e. static type information @ compile time) rather dynamic dispatch (i.e dynamic type information @ runtime).
in code, say, a
placeholder "some type, conforms angle
, determined @ compile time." in first example:
degrees(180) + rotations(0.25) --> degrees(270)
this calls specialized function +<degrees>
. , this:
rotations(0.25) + radians(m_pi) -> rotations(0.75)
calls (logically) different function called +<rotations>
. compiler may choose optimize these functions single function, logically independent functions, created @ compile time. it's shortcut writing adddegrees(degrees, angle)
, addrotations(rotations, angle)
hand.
now, question function takes 2 angles , returns.... well, what? if want return angle
in case, that's easy, , matches original signature:
func +(lhs: angle, rhs: angle) -> angle { return radians(rawradians: lhs.rawradians + rhs.rawradians) }
"but..." you're saying, "that returns radians
." no doesn't. returns angle
. can "angle-like" on want. implementation details opaque should be. if care underlying data structure radians
, you're doing wrong.
ok, there 1 side case may useful know this, , that's if you're printing things out based on how go them. if user gave degree information start, want print in degrees (using description
method didn't mention). , maybe that's worth doing in particular case.if want to, original code close:
func +(lhs: angle, rhs: angle) -> angle { return lhs.dynamictype.init(rawradians: lhs.rawradians + rhs.rawradians) }
but it's critical understand doesn't match request have "the lhs argument dictate return type." causes lhs argument dictate return implementation. return type angle
. if want change return type, need use generics.
Comments
Post a Comment