How to Cast Generic Number Type 'T' to Cgfloat

How to cast generic number type 'T' to CGFloat

As an extension to my answer here, you could achieve this statically through using a 'shadow method' in order to allow Numeric types to coerce themselves to any other Numeric type (given that the initialiser for the destination type is listed as a protocol requirement).

For example, you could define your Numeric protocol like so:

protocol Numeric : Comparable, Equatable {

init(_ v:Float)
init(_ v:Double)
init(_ v:Int)
init(_ v:UInt)
init(_ v:Int8)
init(_ v:UInt8)
init(_ v:Int16)
init(_ v:UInt16)
init(_ v:Int32)
init(_ v:UInt32)
init(_ v:Int64)
init(_ v:UInt64)
init(_ v:CGFloat)

// 'shadow method' that allows instances of Numeric
// to coerce themselves to another Numeric type
func _asOther<T:Numeric>() -> T
}

extension Numeric {

// Default implementation of init(fromNumeric:) simply gets the inputted value
// to coerce itself to the same type as the initialiser is called on
// (the generic parameter T in _asOther() is inferred to be the same type as self)
init<T:Numeric>(fromNumeric numeric: T) { self = numeric._asOther() }
}

And then conform types to Numeric like so:

// Implementations of _asOther() – they simply call the given initialisers listed
// in the protocol requirement (it's required for them to be repeated like this,
// as the compiler won't know which initialiser you're referring to otherwise)
extension Float : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Double : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension CGFloat : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int8 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int16 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int32 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int64 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt8 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt16 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt32 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt64 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}

Example usage:

class MyClass<T : Numeric> {

var top : T

init(_ top:T) {
self.top = top
}

func topAsCGFloat() -> CGFloat {
return CGFloat(fromNumeric: top)
}
}

let m = MyClass(Int32(42))
let converted = m.topAsCGFloat()

print(type(of:converted), converted) // prints: CGFloat 42.0

This solution is probably no shorter than implementing a method that switches through every type that conforms to Numeric – however as this solution doesn't rely on runtime type-casting, the compiler will likely have more opportunities for optimisation.

It also benefits from static type-checking, meaning that you cannot conform a new type to Numeric without also implementing the logic to convert that type to another type of Numeric (in your case, you would crash at runtime if the type wasn't handled in the switch).

Furthermore, because of encapsulation, it's more flexible to expand, as the logic to convert types is done in each individual concrete type that conforms to Numeric, rather than a single method that handles the possible cases.

Casting a variable of generic data type to String in Swift

You can use String interpolation to include value in a String.

class Test<T> {
var value:T
var name: String

init(text: String, val: T) {
name = text
value = val
}

func toString() -> String {
return "\(name): \(value)"
}
}

Unrelated to your issue, but don't declare any of your variables as implicitly unwrapped Optionals (! after their type), especially not when you are setting them in the initializer. You should also conform to the Swift naming convention, which is UpperCamelCase for types (Test).

Is there a way to convert any generic Numeric into a Double?

Just for purposes of syntactical illustration, here's an example of making this a generic and arriving at a Double for all three types:

func f<T:Numeric>(_ i: T) {
var d = 0.0
switch i {
case let ii as Int:
d = Double(ii)
case let ii as Int32:
d = Double(ii)
case let ii as Double:
d = ii
default:
fatalError("oops")
}
print(d)
}

But whether this is better than overloading is a matter of opinion. In my view, overloading is far better, because with the generic we are letting a bunch of unwanted types in the door. The Numeric contract is a lie. A triple set of overloads for Double, Int, and Int32 would turn the compiler into a source of truth.

Swift: Casting a generic, FloatingPoint value to Int

Simple C++ templates are nothing more than a macro-ish, type less, source code replacement mechanism. The calling code is replaced with the applied template and the compiler checks if the resulting code makes any sense. You are right, a roundedInt<T> unbounded function should work fine in C++ land.

Swift generics instead are typesafe by design, meaning the generic code must be sound on its own, independently of any particulars of a given call site. In your example, the FloatingPoint protocol is the type guiding the compilation (and not the actual T type used by the calling code).

(By the way, Java/C# generics also resembles Swift style as well.)


Regarding your actual problem, you could simply provide two overloads for the roundedInt function:

func roundedInt(_ f: Float)  -> Int { ... }
func roundedInt(_ f: Double) -> Int { ... }

which should cover most use cases. Of course, assuming you are only writing small helper functions with this... and not full blown libraries/frameworks!

Otherwise, try @Sweeper string-based solution. But please keep in mind that besides the potential loss of precision he correctly noted, there are also some nasty performance problems lurking in there as well.

How can I handle different types using generic type in swift?

The problem is that T is a generic placeholder – meaning that you cannot know what the actual concrete type of T is from within the function. Therefore although you are able to conditionally cast from and to to a CGRect (thus establishing that T == CGRect), Swift is unable to infer this information and therefore prohibits attempting to return a CGRect when it expects a return of T.

The crude solution therefore is to force cast the return result back to T in order to bridge this gap in information with the type-system:

if let from = from as? CGRect, let to = to as? CGRect {

// ...

return returnRect as! T
}

However, this kind of type-casting is really a sign that you're fighting the type-system and not taking advantage of the static typing that generics offer, and therefore is not recommended.

The better solution, as @Wongzigii has already said, is to use a protocol. For example, if you define an Interpolate protocol as he shows in his answer – you can then use this protocol in order to constrain your generic placeholder T in your interpolate function:

class Interpolation {
class func interpolate<T:Interpolate>(from: T, to: T, progress: CGFloat) -> T {

// Safety
assert(progress >= 0 && progress <= 1, "Invalid progress value: \(progress)")

return T.interpolate(from: from, to: to, progress: progress)
}
}

This solves many of your problems – it does away with the runtime type-casting and instead uses the protocol constraint in order to call the specialised interpolate function. The protocol constraint also prevents you from passing any types that don't conform to Interpolate at compile-time, and therefore also solves the problem of what to do when your type-casting fails.

Although that being said, I actually quite like the solution that @JoshCaswell suggested in his answer to your other question – overloading operators in order to achieve this functionality. As with the previous solution, the key is to define a protocol that encapsulates the functionality you're defining on each type, and then constrain your generic function to this protocol.

A simple implementation may look like this:

protocol Interpolatable {
func +(lhs:Self, rhs:Self) -> Self
func -(lhs:Self, rhs:Self) -> Self
func *(lhs:Self, rhs:CGFloat) -> Self
}

func +(lhs:CGRect, rhs:CGRect) -> CGRect {
return CGRect(x: lhs.origin.x+rhs.origin.x,
y: lhs.origin.y+rhs.origin.y,
width: lhs.size.width+rhs.size.width,
height: lhs.size.height+rhs.size.height)
}

func -(lhs:CGRect, rhs:CGRect) -> CGRect {
return CGRect(x: lhs.origin.x-rhs.origin.x,
y: lhs.origin.y-rhs.origin.y,
width: lhs.size.width-rhs.size.width,
height: lhs.size.height-rhs.size.height)
}

func *(lhs:CGRect, rhs:CGFloat) -> CGRect {
return CGRect(x: lhs.origin.x*rhs,
y: lhs.origin.y*rhs,
width: lhs.size.width*rhs,
height: lhs.size.height*rhs)
}

extension CGRect : Interpolatable {}
extension CGFloat : Interpolatable {}

class Interpolation {
class func interpolate<T:Interpolatable>(from: T, to: T, progress: CGFloat) -> T {
assert(progress >= 0 && progress <= 1, "Invalid progress value: \(progress)")
return from + (to - from) * progress
}
}

Generic with default value of nil

I would do this with two separate intitializers, one of which doesn't need to have an unused generic Z:

struct Vector {
var x: Double
var y: Double
var z: Double?
}

extension Vector {
public init<X: Numeric, Y: Numeric>(_ x: X, _ y: Y) {
self.init(x: x as! Double, y: y as! Double, z: nil as Double?)
}

public init<X: Numeric, Y: Numeric, Z: Numeric>(_ x: X, _ y: Y, _ z: Z? = nil) {
self.init(x: x as! Double, y: y as! Double, z: z as? Double)
}
}

Generic function with switch

Before I went to generic pattern, I'd wonder if you couldn't just use existing FloatingPoint protocol, to which all floating point types already conform:

extension FloatingPoint {
var direction: String {
let value = ((self - 32 / 360) * 16 / 360).rounded()
switch value {
case 0: return "N"
case 1: return "NNE"
case 2: return "NE"
case 3: return "ENE"
case 4: return "E"
case 5: return "ESE"
case 6: return "SE"
case 7: return "SSE"
case 8: return "S"
case 9: return "SSW"
case 10: return "SW"
case 11: return "WSW"
case 12: return "W"
case 13: return "WNW"
case 14: return "NW"
case 15: return "NNW"
case 16: return "N"
default: return "???"
}
}
}

This obviously only works on floating point types, but perhaps this is sufficient for your purposes. If you want, as rmaddy pointed out, you can write a BinaryInteger extension, that casts integer types to floating point types, and it can then use the above:

extension BinaryInteger {
var direction: String {
return Double(Int(self)).direction
}
}

Or you can do a Numeric extension, where they are Comparable, multiplying by some factor so that the threshold values are integers:

extension Numeric where Self: Comparable {
var direction: String {
switch self * 4 {
case 0 ..< 45: return "N"
case 45 ..< 135: return "NNE"
case 135 ..< 225: return "NE"
case 225 ..< 315: return "ENE"
case 315 ..< 405: return "E"
case 405 ..< 495: return "ESE"
case 495 ..< 585: return "SE"
case 585 ..< 675: return "SSE"
case 675 ..< 765: return "S"
case 765 ..< 855: return "SSW"
case 855 ..< 945: return "SW"
case 945 ..< 1035: return "WSW"
case 1035 ..< 1125: return "W"
case 1125 ..< 1215: return "WNW"
case 1215 ..< 1305: return "NW"
case 1305 ..< 1395: return "NNW"
case 1395 ... 1440: return "N"
default: return "???"
}
}
}

Or Alain's approach of multiplying by 100 makes the ranges a little less cryptic.

How can I make Int conform to BinaryFloatingPoint or Double/CGFloat conform to BinaryInteger?

You can add two same functions with different constraint

//T: BinaryInteger & BinaryFloatingPoint
func test<T>(value1: T, value2: T) where T: BinaryInteger{

let someWork = value1 + value2

let intValue: Int = Int(someWork) // <<: Here: I add BinaryInteger because of Int
let doubleValue: Double = Double(someWork) // <<: Here: I add BinaryFloatingPoint because of Double
let cgflotValue: CGFloat = CGFloat(someWork) // <<: Here: I add BinaryFloatingPoint because of CGFloat

print(intValue, doubleValue, cgflotValue)

}
func test<T>(value1: T, value2: T) where T: BinaryFloatingPoint{

let someWork = value1 + value2

let intValue: Int = Int(someWork) // <<: Here: I add BinaryInteger because of Int
let doubleValue: Double = Double(someWork) // <<: Here: I add BinaryFloatingPoint because of Double
let cgflotValue: CGFloat = CGFloat(someWork) // <<: Here: I add BinaryFloatingPoint because of CGFloat

print(intValue, doubleValue, cgflotValue)

}


Related Topics



Leave a reply



Submit