Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending type aliases in swift

Tags:

ios

swift

I am dealing with different units, i.e. distance, altitude, speed, volume, etc.

My goal is to have an elegant, unique way to format them in the app, like for example calling myValue.formatted:

let mySpeed: Speed = 180
println(mySpeed.formatted) // 5.0 km/h

let myAltitude: Altitude = 4000
println(myAltitude.formatted) // 4000 m

I thought this was a good case for using type aliases.

typealias Distance = Float
typealias Altitude = Float
typealias Speed = Float

For the formatted property, I tried with an extension of the type Float:

extension Float {
    var formatted: String {
        get {
            switch self {
            case is Altitude:
                return "\(self) m"
            case is Speed:
                return "\(self * 3.6) km/h"
            default:
                return "\(self)"
            }
        }
    }
}

But the compiler says that my case blocks are always true.

Then i tried to extend the single type:

extension Speed {
  var formatted: String {
    return "\(self * 3.6) km/h"
  }
}
extension Altitude {
  var formatted: String {
    return "\(self) m"
  }
}

the compiler now clearly states Invalid redeclaration of 'formatted'

OK, it's clear now how type aliases work. But how would I get my .formatted property for different types of Floats in swift?

like image 600
gpbl Avatar asked Oct 24 '14 12:10

gpbl


Video Answer


2 Answers

typealias just change or rename the type. It does not create another user type for you. You are actually extending Float for Speed, Altitude again.

You can pass 180 to your custom struct by conforming Literals types.

let mySpeed: Speed = 180

FloatLiteralConvertible and IntegerLiteralConvertible will give you same functionality you want and you can directly assign values to your custom struct types as you assign to Float

struct Speed: FloatLiteralConvertible,IntegerLiteralConvertible {

    var distance:Float
    init(floatLiteral value: Float) {
        distance = value
    }

    init(integerLiteral value: Int){
        distance = Float(value)
    }

    var formatted: String {
        return "\(distance * 3.6) km/h"
    }
}

let mySpeed: Speed = 180.0
println(mySpeed.formatted) // 5.0 km/h
like image 69
codester Avatar answered Oct 20 '22 00:10

codester


Distance, Altitude, and Speed is always the same type - Float and share the same formatted property. This is how compiler sees your code:

extension Float {
    var formatted: String {
        get {
            switch self {
            case is Float:
                return "\(self) m"
            case is Float:
                return "\(self * 3.6) km/h"
            default:
                return "\(self)"
            }
        }
    }
}

I guess you need to create small wrappers for your functionality:

struct Distance {
    var value: Float
    var formatted: String {
        return "\(value) m"
    }

    init(_ value: Float) {
        self.value = value
    }
}

let myDistance = Distance(123)
myDistance.formatted
like image 22
Kirsteins Avatar answered Oct 19 '22 23:10

Kirsteins