[swift-users] Detect if a generic type is numeric

Kevin Lundberg kevin at klundberg.com
Wed Oct 4 20:48:46 CDT 2017


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 at mac.com <mailto:davelist at mac.com>
>>> wrote:
>>>
>>>
>>>
>>>> On Oct 1, 2017, at 2:32 PM, Glenn L. Austin <glenn at austinsoft.com
>>>> <mailto:glenn at austinsoft.com>> wrote:
>>>>
>>>>>
>>>>> On Oct 1, 2017, at 8:56 AM, Dave Reed via swift-users
>>>>> <swift-users at swift.org <mailto:swift-users at swift.org>> wrote:
>>>>>
>>>>>
>>>>>> On Sep 21, 2017, at 3:58 PM, V T via swift-users
>>>>>> <swift-users at swift.org <mailto:swift-users at 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 at swift.org
>>
>> https://lists.swift.org/mailman/listinfo/swift-users
>>
>
>
>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20171004/23d8120c/attachment.html>


More information about the swift-users mailing list