Swift "NSNumber" equivalent?

Under Obj-C I used NSNumbers a lot because it allowed you to convert between various types with ease, and made storage in other collections easy. In Swift many of these limitations have been removed and the built-in base types like Int and Double do much of this. But this means that the generic "Number" isn't there and sometimes this is a useful simplification. So given that the Swift types are value types, and those can be inherited, is there any reason Double and Int couldn't be decendants of Number? Or is such a thing possible now?

>> But this means that the generic "Number" isn't there and sometimes this is a useful simplification.


You can still use NSNumber explicitly in Swift, if you want to.


>> So given that the Swift types are value types, and those can be inherited,


They can't. Double and Int are structs. There is no inheritance for Swift structs.


>> is there any reason Double and Int couldn't be decendants of Number?


They don't really have the same behavior, beyond the basics.


>> Or is such a thing possible now?


You could define your own protocol that includes behavior common to Double and Int, and extend those classes to conform to it. But my guess is that it's going to get pretty ugly, because you'll have trouble with things like literals, unless you make your protocol very complicated.

import Darwin /
struct Number: IntegerLiteralConvertible, FloatLiteralConvertible, StringLiteralConvertible, CustomStringConvertible {
  
    typealias ExtendedGraphemeClusterLiteralType = String
    typealias UnicodeScalarLiteralType = String
  
    enum Type {
        case Int
        case Double
        case Error
    }
    private var _type: Type
    private var _intValue: Int
    private var _doubleValue: Double
    var type: Type { return _type }
    var intValue: Int { return _intValue }
    var doubleValue: Double { return _doubleValue }
    init(_ str: String) {
        if let i = Int(str) {
            _intValue = i
            _doubleValue = Double(i)
            _type = .Int
        } else if let d = Double(str) {
            _doubleValue = d
            _intValue = Int(round(d))
            _type = .Double
        } else {
            _intValue = 0
            _doubleValue = 0
            _type = .Error
        }
    }
    init(_ i: Int) {
        _intValue = i
        _doubleValue = Double(i)
        _type = .Int
    }
    init(_ d: Double) {
        _doubleValue = d
        _intValue = Int(round(d))
        _type = .Double
    }
    init(integerLiteral value: Int) {
        _intValue = value
        _doubleValue = Double(value)
        _type = .Int
    }
    init(floatLiteral value: Double) {
        _doubleValue = value
        _intValue = Int(round(value))
        _type = .Double
    }
    init(stringLiteral value: String) {
        if let d = Double(value), let _ = value.characters.indexOf(".") {
            _doubleValue = d
            _intValue = Int(d)
            _type = .Double
        } else if let i = Int(value) {
            _intValue = i
            _doubleValue = Double(i)
            _type = .Int
        } else {
            _intValue = 0
            _doubleValue = 0
            _type = .Error
        }
    }
  
    init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
        if let d = Double(value) {
            _doubleValue = d
            _intValue = Int(d)
            _type = .Double
        } else if let i = Int(value) {
            _intValue = i
            _doubleValue = Double(i)
            _type = .Int
        } else {
            _intValue = 0
            _doubleValue = 0
            _type = .Error
        }
    }
    init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
        if let d = Double(value) {
            _doubleValue = d
            _intValue = Int(d)
            _type = .Double
        } else if let i = Int(value) {
            _intValue = i
            _doubleValue = Double(i)
            _type = .Int
        } else {
            _intValue = 0
            _doubleValue = 0
            _type = .Error
        }
    }
  
    var description: String {
        switch _type.self {
        case .Int:
            return "\(_intValue)"
        case .Double:
            return "\(_doubleValue)"
        case .Error:
            return "Error"
        }
    }
}
let n1 = Number(10)
let n2 = Number(10.23)
let n3 = Number("11")
let n4 = Number("11.23h")
let n5: Number = 20
let n6: Number = 30.99999999999995
let n7: Number = "11"
let n8: Number = ".511e02"
print(n1, n2, n3, n4, n5, n6, n7, n8)   // 10 10.23 11 Error 20 31.0 11 51.1
n4.type == .Error                       // true
n8.type == .Int                         // false
n8.type == .Double                      // true
print(n8.intValue)                      // 51
print(n4.intValue)                      // 0
print(n4.doubleValue)                   // 0.0
Swift "NSNumber" equivalent?
 
 
Q