[swift-users] How to find out if a property has a default value and what its access levels are during runtime?

exechrome at gmail.com exechrome at gmail.com
Tue Dec 26 16:40:47 CST 2017


Hi-

Inside an init function in a generic protocol extension, I am currently using a Mirror reflecting an instance of “Self" to iterate through all the Child properties of the type adopting the protocol (Self). 

Now, I want to be able to determine how many of Self's properties have a default value prior to any init methods being called. I also would like to know other metadata about these properties, such as what their access level (private/internal/public/open) is, what their ownership is (weak, unowned, etc.), whether they are declared on a parent class or on the existing class/struct/enum, and ideally, get the highest access-level KeyPath to each property under the current scope (since it’s in the type’s own init method now, that scope should be “everything”).

However, so far I am finding Child to be extremely limiting. You can’t get any children of Self.self; you have to reflect an instance. And then, all you get is a string for the key of the property, which evidently cannot even be used to form a KeyPath—not even using the #keypath(String) argument! You don’t get any of the metadata I want via this method, from what I can tell. Am I missing something…? 

Forgetting about generic protocols for a second, even with a concrete type, I can’t seem to figure out how one would be able to use KeyPaths in the manner that I’m trying to do. Here is an example showing some of these limitations:

struct Foo {
    private(set) var hasDefaultValue = true
    private(set) var doesNotHaveDefaultValue: Bool
    var default = Foo(hasDefaultValue: true, doesNotHaveDefaultValue: false)
}

init() {
    for child in Mirror(reflecting: Foo.default) {
        let key = #keypath(“Foo.” + child.label) // won’t compile; worthless
        let path: WritableKeyPath<Foo, Bool> = \Foo.doesNotHaveDefaultValue // compiles, so far so good… (false hope)
        self[keyPath: path] = false // crashes even though it’s a WritableKeyPath; worthless
	… etc. etc.
    }
}

Are these just bugs? Or is keyPath really this limited? Is there really no way in Swift to use reflection to get all the information on a type’s properties, not even from within the type’s own init method?

So far it seems that Mirror just returns for each property<T> a (label: String, value: T) tuple where label is just a String, and value is whatever type the property is. Meanwhile, in the C++ of the open source Swift compiler code, they have a method allowing the compiler to determine whether or not a property has a default value. I just want to know if there’s a way to do it from within Swift, or if all these goodies are still only available in C++. If I need to submit a PR to mod the compiler then I will, I just want to make sure I’m not missing something here.

Thanks,

Jon


More information about the swift-users mailing list