apple / swift-numerics

Advanced mathematical types and functions for Swift

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CGFloat Does not conform to Real

Peter-Schorn opened this issue · comments

Are there any plans to conform CGFloat to Real?

Presumably the implementation would look something like this:

extension CGFloat: Real {

  @_transparent
  public static func cos(_ x: CGFloat) -> CGFloat {
     CGFloat(CGFloat.NativeType.cos(x.native))
  }

  // ...

}

This would be easy to add, but as a general rule, you shouldn't be using CGFloat except at the point of interaction with API that traffics in it. We don't want to encourage people to write significant code that uses CGFloat as a computational type. What are you really trying to do?

I admit I don't have a concrete use-case for this; I was just worried I might have to use this library with SwiftUI or UIKit, which uses CGFloat.

As perhaps a useful update to this thread to new visitors, Swift 5.5 will make CGFloat and Double interchangeable, making it easy to follow Stephen Canon's recommendation of not using CGFloat as a computational type.

In the rare case when CGFloat represents a 32-bit float, requiring a widening or narrowing conversions, the compiler will try to maintain as much precision as possible by minimizing the number of narrowing conversions.

https://github.com/apple/swift-evolution/blob/main/proposals/0307-allow-interchangeable-use-of-double-cgfloat-types.md

@Peter-Schorn I'm going to close this for now.

Let's say i want to write a generic linear interpolation function using Real:

public func lerp<T>(_ parameter: T, min: T, max: T) -> T where T: Real
{
    return min + (parameter * (max - min))
}

Now if i want to use it with CGFloat obtained from graphics api (let's say a position of 2 SpriteKit nodes on a specific axis) i would need to manually cast either one of the arguments to Dobule when calling lerp or on obtaining them or specify result type as Double or write a CGFloat specific wrapper function,

let minX: CGFloat = ...
let maxX: CGFloat = ...
let parmeter: CGFloat = ...

let result = lerp(Double(parameter), min: minX, max: maxX)
// or
let result: Double = lerp(parameter, min: node1X, max: node2X)

This is not really a problem but seems unnecessary despite the SE-0307. Besides conforming CGFloat to Real is rather easy.

While computation code written specifically for graphic computations could (and perhaps should) be written exclusively for CGFloat, i'd prefer a generic solution that could be used for all real types without any type casting workarounds.

We don't really want to be doing computation in CGFloat; that's not what it's for. It's for interacting with existing graphics APIs. The point of SE-0307 is to make it easier for these conversions to happen at the site of those API calls, so that you can do the rest of your computation in either Float or Double.