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
Overloads for '...' Exist with These Result Types: Closedrange<Bound>, Countableclosedrange<Bound>
How to Use Implicitly Unwrapped Optionals
Why Is Uint64 Max Equal -1 in Swift
Swift 3 - How to Write Functions with No Initialisers Like the New Uicolors
How to Extend Float3 or Any Other Built-In Type to Conform to the Codable Protocol
Swift 2 Mkmapviewdelegate Rendererforoverlay Optionality
Swift Associated Types and Protocol Inheritance
Why Specify [Unowned Self] in Blocks Where You Depend on Self Being There
Is There *Any* Situation Under Which "For _ in [1,2,3]" Will Not Loop at All
Openinmapswithlaunchoptions Not Working
How to Add a Left Bar Button Without Overriding the Natural Back Button
Why Is There a "Plus" Icon at the Top Right Corner of My View
How to Set Width and Height of an Image in Swiftui
Load Image from Url on Watchkit
Find Out When Uikeyboard.Frame Intersects with Other Frame
How to Add Openssl to a Swift Project
Use Quick Look Inside a Swift Cocoa Application to Preview Audio Files