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