Binding<T>: how to determine wrappedValue is signed numeric value?

I'm passing around a Binding<T>, where T is numeric value types that NSNumber can handle/support. I need to know if its wrappedValue is signed numeric.

This doesn't work:

extension Binding {
    var isSignedNumeric: Bool {
           wrappedValue is SignedNumeric.  // error: SignedNumeric has `Self` or PAT
    }
}

I'm dong this now:

extension Binding {
    var isSignedNumeric: Bool {
           wrappedValue is Double
        || wrappedValue is Float
        || wrappedValue is Int32
        || wrappedValue is Int
        || wrappedValue is Int64
        || wrappedValue is Int16
    }
}

Is there better way?

1 Like

What exactly do you plan on doing with the value, once you know whether or not it is signed?

This comment explains how you can test for conformance to a PAT, and has links for how to actually do things with that conformance.

But if you are working with a fixed set of known types, you might want to just make your own protocol and conform them to it.

For conditionally showing the right UI. I'm working with this kind of SwiftUI.TextField:

TextField.init<S, T>(_ title: S, value: Binding, formatter: Formatter)

with .keyboardType(.numberPad) attached to the TextField for entering numbers only. The .numberPad keyboard only has numbers 0-9 and delete and nothing else. I'm adding a keyboard toolbar to allow entering negative value only when the type is signed.

I have access to the binding of the TextField.

T can only be the types NSNumber can handle excluding Bool and Char, these:

Double
Float
Int32
Int
Int64
Int16
UInt8
UInt32
UInt
UInt64
UInt16

I don't know how to constrain T to only these, so I do this T: Numeric but Numeric is not exactly the type above. Or T totally unconstrained, like the TextField.init above.

You make a new protocol with the semantics you want (eg. NSNumberConvertible) and conform the types you want to it.

1 Like

Thank you! This solve my problem:

protocol NSNumberConvertible { }
protocol SignedNSNumberConvertible: NSNumberConvertible { }
protocol UnsignedNSNumberConvertible: NSNumberConvertible { }

// can do this now
...  wrappedValue is SignedNSNumberConvertible ...

this also solve my other problem :raised_hands:

For learning, I took your code and changed a little to make it work for test if is SignNumeric:

protocol SignedNumericConformanceMarker {}
enum SignedNumericMarker<T> {}
extension SignedNumericMarker: SignedNumericConformanceMarker where T: SignedNumeric {}

func isSignedNumericType<T>(_ t: T.Type) -> Bool {
    return SignedNumericMarker<T>.self is SignedNumericConformanceMarker.Type
}

func isSignedNumeric<T>(_ t: T) -> Bool {
    return isSignedNumericType(T.self)
}

let u: UInt = 0
let i = 0

print("isSignedNumeric(u)", isSignedNumeric(u))     // print: isSignedNumeric(u) false
print("isSignedNumeric(i)", isSignedNumeric(i))     // print: isSignedNumeric(i) true

// make it a little fluent
extension Numeric {
    var isSigned: Bool {
        isSignedNumeric(self)
    }
}

print("u.isSigned", u.isSigned)
print("i.isSigned", i.isSigned)

very interesting how you build thing up and then go from T to T.Type. I can never be able to come up with code like this.

:pray::bowing_woman:t2: