Detect if a generic type is numeric

Hi there!

Is there a best way to check if a given type conforms to numeric protocol (Integer or FP) at runtime?

func checkNumeric<T>(_ value: T) {
  /* return true if vaiue is Integer or FP */
  /* this will not compile: */
  if value is Numeric {
    
  }
}

Best regards!

VT

I think the way to do it is to try casting as the type, but you can't use "as? Numeric" as you get:

error: protocol 'Numeric' can only be used as a generic constraint because it has Self or associated type requirements

but you could check for each specific numeric type such as:

func checkNumeric<T>(_ value: T) {
    if (value as? Int != nil) || (value as? Float != nil) {
        print("numeric")
    } else {
        print("not numeric")
    }
}

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

HTH,
Dave

···

On Sep 21, 2017, at 3:58 PM, V T via swift-users <swift-users@swift.org> wrote:

Hi there!

Is there a best way to check if a given type conforms to numeric protocol (Integer or FP) at runtime?

func checkNumeric<T>(_ value: T) {
  /* return true if vaiue is Integer or FP */
  /* this will not compile: */
  if value is Numeric {
    
  }
}

Best regards!

VT

You can also use the 'is' operator, as in 'value is Int || value is Float || value is Double'

···

On Oct 1, 2017, at 8:56 AM, Dave Reed via swift-users <swift-users@swift.org> wrote:

On Sep 21, 2017, at 3:58 PM, V T via swift-users <swift-users@swift.org> wrote:

Hi there!

Is there a best way to check if a given type conforms to numeric protocol (Integer or FP) at runtime?

func checkNumeric<T>(_ value: T) {
  /* return true if vaiue is Integer or FP */
  /* this will not compile: */
  if value is Numeric {
    
  }
}

Best regards!

VT

I think the way to do it is to try casting as the type, but you can't use "as? Numeric" as you get:

error: protocol 'Numeric' can only be used as a generic constraint because it has Self or associated type requirements

but you could check for each specific numeric type such as:

func checkNumeric<T>(_ value: T) {
   if (value as? Int != nil) || (value as? Float != nil) {
       print("numeric")
   } else {
       print("not numeric")
   }
}

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

--
Glenn L. Austin, Computer Wizard, AustinSoft.com

Ah, I had forgotten "is" works in Swift

Just be careful as:

func checkNumeric<T>(_ value: T) {
    if (value is Int) || (value is Float) {
        print("numeric")
    } else {
        print("not numeric")
    }
}

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

outputs:

numeric
not numeric
not numeric

Since the literal 3.0 is a Double so you'd have to catch every floating point type (including CGFloat, I suspect etc.) vs. just trying to cast to a Float (although I guess casting to a Float could have unexpected results also if someone made an extension that allows a type to be cast as a Float).

Dave

···

On Oct 1, 2017, at 2:32 PM, Glenn L. Austin <glenn@austinsoft.com> wrote:

On Oct 1, 2017, at 8:56 AM, Dave Reed via swift-users <swift-users@swift.org> wrote:

On Sep 21, 2017, at 3:58 PM, V T via swift-users <swift-users@swift.org> wrote:

Hi there!

Is there a best way to check if a given type conforms to numeric protocol (Integer or FP) at runtime?

func checkNumeric<T>(_ value: T) {
  /* return true if vaiue is Integer or FP */
  /* this will not compile: */
  if value is Numeric {
    
  }
}

Best regards!

VT

I think the way to do it is to try casting as the type, but you can't use "as? Numeric" as you get:

error: protocol 'Numeric' can only be used as a generic constraint because it has Self or associated type requirements

but you could check for each specific numeric type such as:

func checkNumeric<T>(_ value: T) {
   if (value as? Int != nil) || (value as? Float != nil) {
       print("numeric")
   } else {
       print("not numeric")
   }
}

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

You can also use the 'is' operator, as in 'value is Int || value is Float || value is Double'

--
Glenn L. Austin, Computer Wizard, AustinSoft.com

Hi there!

Is there a best way to check if a given type conforms to numeric protocol (Integer or FP) at runtime?

func checkNumeric<T>(_ value: T) {
  /* return true if vaiue is Integer or FP */
  /* this will not compile: */
  if value is Numeric {
    
  }
}

Best regards!

VT

I think the way to do it is to try casting as the type, but you can't use "as? Numeric" as you get:

error: protocol 'Numeric' can only be used as a generic constraint because it has Self or associated type requirements

but you could check for each specific numeric type such as:

func checkNumeric<T>(_ value: T) {
  if (value as? Int != nil) || (value as? Float != nil) {
      print("numeric")
  } else {
      print("not numeric")
  }
}

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

You can also use the 'is' operator, as in 'value is Int || value is Float || value is Double'

--
Glenn L. Austin, Computer Wizard, AustinSoft.com

Ah, I had forgotten "is" works in Swift

Just be careful as:

func checkNumeric<T>(_ value: T) {
   if (value is Int) || (value is Float) {
       print("numeric")
   } else {
       print("not numeric")
   }
}

Thanks all! My current implementation looks like this. A bit redundant, bat it works. My intention was to simplify that monster:

func isNumber<T>(_ value: T) -> Bool {
    let valueMirror = Mirror(reflecting: value)
    if arch(arm) || arch(arm64)
        if (valueMirror.subjectType == Int.self || valueMirror.subjectType == UInt.self || valueMirror.subjectType == Double.self || valueMirror.subjectType == Int8.self || valueMirror.subjectType == Int16.self || valueMirror.subjectType == Int32.self || valueMirror.subjectType == Int64.self || valueMirror.subjectType == UInt8.self || valueMirror.subjectType == UInt16.self || valueMirror.subjectType == UInt32.self || valueMirror.subjectType == UInt64.self || valueMirror.subjectType == Float.self || valueMirror.subjectType == Float32.self || valueMirror.subjectType == NSNumber.self || valueMirror.subjectType == NSDecimalNumber.self ) {
            return true
        }
        else {
            return false
        }
    #else
        if (valueMirror.subjectType == Int.self || valueMirror.subjectType == UInt.self || valueMirror.subjectType == Double.self || valueMirror.subjectType == Int8.self || valueMirror.subjectType == Int16.self || valueMirror.subjectType == Int32.self || valueMirror.subjectType == Int64.self || valueMirror.subjectType == UInt8.self || valueMirror.subjectType == UInt16.self || valueMirror.subjectType == UInt32.self || valueMirror.subjectType == UInt64.self || valueMirror.subjectType == Float.self || valueMirror.subjectType == Float32.self || valueMirror.subjectType == Float80.self || valueMirror.subjectType == NSNumber.self || valueMirror.subjectType == NSDecimalNumber.self ) {
            return true
        }
        else {
            return false
        }
    #endif
}

···

On 1. Oct 2017, at 22:43, davelist@mac.com wrote:

On Oct 1, 2017, at 2:32 PM, Glenn L. Austin <glenn@austinsoft.com> wrote:

On Oct 1, 2017, at 8:56 AM, Dave Reed via swift-users <swift-users@swift.org> wrote:

On Sep 21, 2017, at 3:58 PM, V T via swift-users <swift-users@swift.org> wrote:

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

outputs:

numeric
not numeric
not numeric

Since the literal 3.0 is a Double so you'd have to catch every floating point type (including CGFloat, I suspect etc.) vs. just trying to cast to a Float (although I guess casting to a Float could have unexpected results also if someone made an extension that allows a type to be cast as a Float).

Dave

Can you do something like this?

func isNumber<T: Numeric>(_ value: T) -> Bool { return true }

func isNumber<T>(_ value: T) -> Bool { return false }

I don't recall whether or not swift will pick the right version of the
function here, or whether this can even compile (mac isnt open at the
moment), but if you can overload functions in this way then it might be
much nicer than checking for lots of concrete types.

···

On 10/1/2017 6:27 PM, V T via swift-users wrote:

On 1. Oct 2017, at 22:43, davelist@mac.com <mailto:davelist@mac.com> >> wrote:

On Oct 1, 2017, at 2:32 PM, Glenn L. Austin <glenn@austinsoft.com >>> <mailto:glenn@austinsoft.com>> wrote:

On Oct 1, 2017, at 8:56 AM, Dave Reed via swift-users >>>> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

On Sep 21, 2017, at 3:58 PM, V T via swift-users >>>>> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hi there!

Is there a best way to check if a given type conforms to numeric
protocol (Integer or FP) at runtime?

func checkNumeric<T>(_ value: T) {
/* return true if vaiue is Integer or FP */
/* this will not compile: */
if value is Numeric {

}
}

Best regards!

VT

I think the way to do it is to try casting as the type, but you
can't use "as? Numeric" as you get:

error: protocol 'Numeric' can only be used as a generic constraint
because it has Self or associated type requirements

but you could check for each specific numeric type such as:

func checkNumeric<T>(_ value: T) {
��if (value as? Int != nil) || (value as? Float != nil) {
������print("numeric")
��} else {
������print("not numeric")
��}
}

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

You can also use the 'is' operator, as in 'value is Int || value is
Float || value is Double'

--
Glenn L. Austin, Computer Wizard, AustinSoft.com <http://AustinSoft.com>

Ah, I had forgotten "is" works in Swift

Just be careful as:

func checkNumeric<T>(_ value: T) {
���if (value is Int) || (value is Float) {
�������print("numeric")
���} else {
�������print("not numeric")
���}
}

Thanks all! My current implementation looks like this. A bit
redundant, bat it works. My intention was to simplify that monster:

func isNumber<T>(_ value: T) -> Bool {
� � let valueMirror = Mirror(reflecting: value)
� � #ifarch(arm) || arch(arm64)
� � � � if (valueMirror.subjectType == Int.self ||
valueMirror.subjectType == UInt.self || valueMirror.subjectType ==
Double.self || valueMirror.subjectType == Int8.self ||
valueMirror.subjectType == Int16.self || valueMirror.subjectType ==
Int32.self || valueMirror.subjectType == Int64.self ||
valueMirror.subjectType == UInt8.self || valueMirror.subjectType ==
UInt16.self || valueMirror.subjectType == UInt32.self ||
valueMirror.subjectType == UInt64.self || valueMirror.subjectType ==
Float.self || valueMirror.subjectType == Float32.self ||
valueMirror.subjectType == NSNumber.self || valueMirror.subjectType ==
NSDecimalNumber.self ) {
� � � � � � return true
� � � � }
� � � � else {
� � � � � � return false
� � � � }
� � #else
� � � � if (valueMirror.subjectType == Int.self ||
valueMirror.subjectType == UInt.self || valueMirror.subjectType ==
Double.self || valueMirror.subjectType == Int8.self ||
valueMirror.subjectType == Int16.self || valueMirror.subjectType ==
Int32.self || valueMirror.subjectType == Int64.self ||
valueMirror.subjectType == UInt8.self || valueMirror.subjectType ==
UInt16.self || valueMirror.subjectType == UInt32.self ||
valueMirror.subjectType == UInt64.self || valueMirror.subjectType ==
Float.self || valueMirror.subjectType == Float32.self ||
valueMirror.subjectType == Float80.self || valueMirror.subjectType ==
NSNumber.self || valueMirror.subjectType == NSDecimalNumber.self ) {
� � � � � � return true
� � � � }
� � � � else {
� � � � � � return false
� � � � }
� � #endif
}

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

outputs:

numeric
not numeric
not numeric

Since the literal 3.0 is a Double so you'd have to catch every
floating point type (including CGFloat, I suspect etc.) vs. just
trying to cast to a Float (although I guess casting to a Float could
have unexpected results also if someone made an extension that allows
a type to be cast as a Float).

Dave

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Scratch that, that won't work for the runtime type:

isNumeric(0 as Any) == false // :(

···

On 10/4/2017 9:30 PM, Kevin Lundberg via swift-users wrote:

Can you do something like this?

func isNumber<T: Numeric>(_ value: T) -> Bool { return true }

func isNumber<T>(_ value: T) -> Bool { return false }

I don't recall whether or not swift will pick the right version of the
function here, or whether this can even compile (mac isnt open at the
moment), but if you can overload functions in this way then it might
be much nicer than checking for lots of concrete types.

On 10/1/2017 6:27 PM, V T via swift-users wrote:

On 1. Oct 2017, at 22:43, davelist@mac.com <mailto:davelist@mac.com> >>> wrote:

On Oct 1, 2017, at 2:32 PM, Glenn L. Austin <glenn@austinsoft.com >>>> <mailto:glenn@austinsoft.com>> wrote:

On Oct 1, 2017, at 8:56 AM, Dave Reed via swift-users >>>>> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

On Sep 21, 2017, at 3:58 PM, V T via swift-users >>>>>> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Hi there!

Is there a best way to check if a given type conforms to numeric
protocol (Integer or FP) at runtime?

func checkNumeric<T>(_ value: T) {
/* return true if vaiue is Integer or FP */
/* this will not compile: */
if value is Numeric {

}
}

Best regards!

VT

I think the way to do it is to try casting as the type, but you
can't use "as? Numeric" as you get:

error: protocol 'Numeric' can only be used as a generic constraint
because it has Self or associated type requirements

but you could check for each specific numeric type such as:

func checkNumeric<T>(_ value: T) {
��if (value as? Int != nil) || (value as? Float != nil) {
������print("numeric")
��} else {
������print("not numeric")
��}
}

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

You can also use the 'is' operator, as in 'value is Int || value is
Float || value is Double'

--
Glenn L. Austin, Computer Wizard, AustinSoft.com
<http://AustinSoft.com>

Ah, I had forgotten "is" works in Swift

Just be careful as:

func checkNumeric<T>(_ value: T) {
���if (value is Int) || (value is Float) {
�������print("numeric")
���} else {
�������print("not numeric")
���}
}

Thanks all! My current implementation looks like this. A bit
redundant, bat it works. My intention was to simplify that monster:

func isNumber<T>(_ value: T) -> Bool {
� � let valueMirror = Mirror(reflecting: value)
� � #ifarch(arm) || arch(arm64)
� � � � if (valueMirror.subjectType == Int.self ||
valueMirror.subjectType == UInt.self || valueMirror.subjectType ==
Double.self || valueMirror.subjectType == Int8.self ||
valueMirror.subjectType == Int16.self || valueMirror.subjectType ==
Int32.self || valueMirror.subjectType == Int64.self ||
valueMirror.subjectType == UInt8.self || valueMirror.subjectType ==
UInt16.self || valueMirror.subjectType == UInt32.self ||
valueMirror.subjectType == UInt64.self || valueMirror.subjectType ==
Float.self || valueMirror.subjectType == Float32.self ||
valueMirror.subjectType == NSNumber.self || valueMirror.subjectType
== NSDecimalNumber.self ) {
� � � � � � return true
� � � � }
� � � � else {
� � � � � � return false
� � � � }
� � #else
� � � � if (valueMirror.subjectType == Int.self ||
valueMirror.subjectType == UInt.self || valueMirror.subjectType ==
Double.self || valueMirror.subjectType == Int8.self ||
valueMirror.subjectType == Int16.self || valueMirror.subjectType ==
Int32.self || valueMirror.subjectType == Int64.self ||
valueMirror.subjectType == UInt8.self || valueMirror.subjectType ==
UInt16.self || valueMirror.subjectType == UInt32.self ||
valueMirror.subjectType == UInt64.self || valueMirror.subjectType ==
Float.self || valueMirror.subjectType == Float32.self ||
valueMirror.subjectType == Float80.self || valueMirror.subjectType ==
NSNumber.self || valueMirror.subjectType == NSDecimalNumber.self ) {
� � � � � � return true
� � � � }
� � � � else {
� � � � � � return false
� � � � }
� � #endif
}

checkNumeric(3)
checkNumeric(3.0)
checkNumeric("3")

outputs:

numeric
not numeric
not numeric

Since the literal 3.0 is a Double so you'd have to catch every
floating point type (including CGFloat, I suspect etc.) vs. just
trying to cast to a Float (although I guess casting to a Float could
have unexpected results also if someone made an extension that
allows a type to be cast as a Float).

Dave

_______________________________________________

swift-users mailing list

swift-users@swift.org

https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

It’ll compile, but you’ll get the wrong answer if it’s called from another generic function that isn’t similarly overloaded for `T` vs `T: Numeric`. I’m not at my computer right now, but IIRC, this is correct:

func foo<T> (_ value:T) -> Bool {
    return isNumber(value)
}
func bar<T> (_ value:T) -> Bool {
    return isNumber(value)
}
func bar<T: Numeric> (_ value:T) -> Bool {
    return isNumber(value)
}
isNumber(0) //true
isNumber(“”) //false
foo(0) //false
foo(“”) //false
bar(0) //true
bar(“”) //false

- Dave Sweeris

···

On Oct 4, 2017, at 18:30, Kevin Lundberg via swift-users <swift-users@swift.org> wrote:

Can you do something like this?

func isNumber<T: Numeric>(_ value: T) -> Bool { return true }

func isNumber<T>(_ value: T) -> Bool { return false }

I don't recall whether or not swift will pick the right version of the function here, or whether this can even compile (mac isnt open at the moment), but if you can overload functions in this way then it might be much nicer than checking for lots of concrete types.

That was my point... `foo` doesn’t have a `T: Numeric` version, therefore when it calls `isNumeric` the compiler has to call the version that always return false. `bar` is overloaded with both a `T` and a `T: Numeric` version, so there the compiler can call the most appropriate version of `isNumeric`.

- Dave Sweeris

···

On Oct 5, 2017, at 01:49, Alex Blewitt <alblue@apple.com> wrote:

I think one of your 'foo' or 'bar' is missing a <T:Numeric>, as otherwise the functions are identical ...

Alex

On 5 Oct 2017, at 09:23, David Sweeris via swift-users <swift-users@swift.org> wrote:

On Oct 4, 2017, at 18:30, Kevin Lundberg via swift-users <swift-users@swift.org> wrote:

Can you do something like this?

func isNumber<T: Numeric>(_ value: T) -> Bool { return true }

func isNumber<T>(_ value: T) -> Bool { return false }

I don't recall whether or not swift will pick the right version of the function here, or whether this can even compile (mac isnt open at the moment), but if you can overload functions in this way then it might be much nicer than checking for lots of concrete types.

It’ll compile, but you’ll get the wrong answer if it’s called from another generic function that isn’t similarly overloaded for `T` vs `T: Numeric`. I’m not at my computer right now, but IIRC, this is correct:

func foo<T> (_ value:T) -> Bool {
    return isNumber(value)
}
func bar<T> (_ value:T) -> Bool {
    return isNumber(value)
}
func bar<T: Numeric> (_ value:T) -> Bool {
    return isNumber(value)
}
isNumber(0) //true
isNumber(“”) //false
foo(0) //false
foo(“”) //false
bar(0) //true
bar(“”) //false

- Dave Sweeris
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

See my solution:
import UIKit
func isNumeric(_ value: Any) -> Bool {
let numericTypes: [Any.Type] = [Int.self, Int8.self, Int16.self, Int32.self, Int64.self, UInt.self, UInt8.self, UInt16.self, UInt32.self, UInt64.self, Double.self, Float.self, Float32.self, Float64.self, Decimal.self, NSNumber.self, NSDecimalNumber.self]
return numericTypes.contains { $0 == Mirror(reflecting: value).subjectType }
}

1 Like