user3763801
user3763801

Reputation: 395

How to produce a nil of a generic type

I would like to declare a generic class which holds/obtains a variable of type Any?, but casts this variable to a given type, when requested. Something like this

class A<T> {
    var o: NSObject!
    var k: String!
    var v: T {
        get { return o.value(forKeyPath: k) as! T }
        set { o.setValue(newValue, forKeyPath: k) }
    }
}

I would like to this to work so that when o.value(forKeyPath: k) is nil and T can hold a nil (it is ExpressibleByNilLiteral), v returns nil (of type T). As it is, it crashes because of the as!. Is it possible to do this?

An attempted crack at this looks like this (suggested by How to make a computed property of a generic class depend on the class constraints)

class A<T> {
    var o: NSObject!
    var k: String!
    var v: T {
        get { 
            let x = o.value(forKeyPath: k)
            if let E = T.self as? ExpressibleByNilLiteral.Type {
                if let x = x { return x as! T }
                let n: T = <nil of type T> <---- not sure what to put here
                return n
            } else {
                return x as! T 
            }
        }
        set { o.setValue(newValue, forKeyPath: k) }
    }
}

but I am not sure how to make it work.

Upvotes: 0

Views: 673

Answers (1)

user3763801
user3763801

Reputation: 395

Not sure why, but this actually works

func cast<T>(_ v: Any?)->T {
    if let E = T.self as? ExpressibleByNilLiteral.Type {
        if let v = v {
            return v as! T
        } else {
            return E.init(nilLiteral: ()) as! T
        }
    } else {
        return v as! T
    }
}

I thought I already tried this and it did not work... Anyway, now we can substitute all as! calls with cast when we do not want to crash on nil, if the type we are casting to can take it, e.g. in the getter of my question.

Upvotes: 1

Related Questions