Creating KeyPaths at Runtime

Recently I've been eyeing StoredPropertyIterable after playing around with Swift's metadata capabilities, and my only question was how to create keypaths at runtime? I found swift_getKeyPath, but it requires a keypath pattern in order to instantiate, but I'm unsure how to construct such patterns because they're statically emitted in the resulting binary. Not to mention that it'd be ideal to create a keypath once cache for trivially computed ones like the compiler emits. cc: @Joe_Groff

5 Likes

I've also been playing with Swift's runtime metadata and I was wondering how to construct a key path object from a type metadata and a member offset. @Alejandro did you have any luck deciphering this?

The layout of the KeyPath class is not ABI stable, and I don't think we have sufficient API to be able to create key paths outside of the standard library and runtime today. If you want to create stored property keypaths at runtime, we could add a runtime entry point that creates a key path given a KeyPath class and a field offset. You would probably want to do your own caching, since the once caches the compiler emits only really make sense for static literals that appear in the code.

1 Like

Yeah, I was able to do something to create keypaths at runtime, but as Joe said the runtime layout of keypaths are not ABI stable. Plus, there are types of keypaths that are simply not possible to create at runtime including ones to weak/unowned references, correct subclass keypaths, etc. I’m currently working with some of the Swift 4 Tensorflow folks to bring this functionality to the standard library/ a reflection library shipped with the language (I don’t think we have concrete plans at the moment for where we want to put it). I think it makes more sense to implement a runtime entry point like Joe mentioned.

It should be possible to dynamically create weak/unowned keypaths. They are modeled as computed property components, but you could provide a generic getter/setter implementation that handles the weak or unowned load, using an offset into the container you capture in the key path object as an argument to the implementation function. For equality and hashing, these key paths use the offset of the reference storage in the containing object as an identifier. So we could have a swift_createUnownedStoredKeyPath entry point that constructs such a key path given a type and offset as well. It might also be possible to dynamically handle class property key paths because the method information for their getter/setter should be available in the method descriptors of the class.

1 Like

Oh wow I feel dumb now. I forgot that I could model my own computed properties! In my head I was trying to model these keypath getters/setters as how the compiler models them void (OpaqueValue *return, OpaqueValue *source_struct), but felt I was unable to do this because there's no way to retrieve the desired offset and type metadata with this information. However, if I just crafted my own computed keypaths that takes an offset argument... :sweat:

Yeah, the key path getter/setters in their full generality also receive a pointer to the key path component's argument area inside the key path object, so you can store any additional arbitrary data you want to pass to your implementation functions there. This is how subscripts and key paths in unspecialized generic contexts recover their subscript index and contextual type information.