SE-0438: Metatype keypaths

Sure, that’s fair but cannot be 6 though, if we can get precise compiler version I am not against using that!

2 Likes

But the case that's problematic is if you have a binary framework + .swiftinterface that was built with an older compiler, and you're consuming it with a newer compiler and trying to use a static keypath into the older framework, right?

That’s right.

We considered property descriptor symbol emission directly into the client but it’s the same problem where we don’t know whether the module has them as well and if it does how to reconcile.

@tshortli Do you know if it’s possible to inject these symbols into the module during rebuild from swiftinterface?

We have a test-case checked-in right now that uses host compiler to build LibA with library evolution enabled and then uses target compiler to build LibB and LibC that reference static properties from LibA in their key paths.

Maybe I've confused myself with Slava's question and now I'm thinking that it's pretty much all we care about when it comes to older libraries because we don't support non-library evolution because we cannot load older modules and rebuilding already works as expected...

Edit: To clarify - the problem here is that on Darwin the dynamic library of the framework the client links against is supposed to have property descriptor symbols available when building the client even though the client has a weak link against it. With our current setup it should be possible to back deploy previously built client to older version of the library because key path itself also carries all of the required info but it won't be possible to link against the old library while building it...

@amritpan as @allevato suggests we should bump SWIFTMODULE_VERSION_MINOR as well, we missed that unintentionally.

1 Like

In the example given in the proposal that seems unambiguous as the species property already returns a type, and not an instance. That means the last part of the KeyPath cannot refer to non-static property of Species as there's no instance delivered by the second-to-last.

However, I would be interested how I can understand the proposal if we want to make deeper KeyPaths:

struct Wasp {
  static let queenOfMean = true
}

struct Insect {
  static let theAskhole = Wasp()
}

let weNeedToGoDeeper = \Insect.Type.theAskhole.Type.queenOfMean

Is this an intended syntax for the proposal? Not that I'd see a usecase necessarily, I am just asking to understand.

2 Likes

Oh you’re right, I hadn’t noticed it was a type. Thanks for clearing it up.

1 Like

Not at the moment, .Type is only intended for the root, otherwise key paths behave like regular member chains that cannot switch access like that.

I was thinking about this some more - for the scenario we care about were swiftmodule gets rebuilt from the swiftinterface the module would claim that its build with compiler new enough to support this feature but the underlying dynamic or static library won't have the symbol because it doesn't get rebuilt...

The version of the compiler that emitted the textual interface is printed in the interface, so there shouldn’t be an issue correctly identifying which version of the compiler produced the dylib and therefore whether or not these extra symbols will be present at link time.

1 Like

Ah, perfect! I didn't know that it was accessible, I'll reach out to you separately to flash out the details.

Thanks & perfect, I'd say this clarification should perhaps go into the proposal and/or later documentation.

For me the proposal in total gets a strong +1 even without that (as said, I don't see a proper use-case for "chaining" these kinds of keypaths). To formally answer the bullet points for a review:

  • I think this is a good proposal that should be added to the language. It's scope is small and the reasoning sound.
  • Personally I think the addressed problem is of the smaller kind, but the proposed changes are adequately sized in scope. I.e. I don't see any problematic side-effects of the proposal that could affect other areas of the language and the way we can express KeyPaths to static properties with this are not at risk to collide with other syntax.
  • I don't know other languages or libraries with a similar structure yet, but the proposed use of .Type fits well to Swift in general, as we use this syntax in plenty other spaces. It's "swifty".
  • I read the proposal twice and also followed the comments in this thread so far. This also alleviated any concerns I initially had about source compatibility.
2 Likes

Yes, we will see the following error if you miss .Type while calling a static component as your first component with a fix-it to add .Type after root type T:

let _ = \T.staticProperty // error: static member 'staticProperty' cannot be used on instance of type 'T' "

I have added this to the proposal.

This is a valid observation. I have updated all of the references in this proposal text to use KeyPath for now.

Thank you for the suggestions!

We will be adding the following to the proposal text to address implications on adoption:

This feature is back-deployable but it requires emission of new (property descriptors) symbols for static properties.

The type-checker wouldn't allow to form key paths to static properties of types that come from modules that are built by an older compiler that don't support the feature because dynamic or static library produced for such module won't have all of the required symbols.

Attempting to form a key path to a static property of a type from a module compiled with a complier that doesn't yet support the feature will result in the following error with a note to help the developers:

error: cannot form a keypath to a static property <Property> of type <Type>
note: rebuild <Module> to enable the feature
4 Likes