Import declarations

It is possible to have import declarations of class members? Or it just works for global symbols?

Example:
UILabel has a member shadowOffset: CGSize and we have an extension on UIView that declares the extension on an external module. So I thought it would be possible to disambiguate that using a declaration import e.g.

import var UIKit.UILabel.shadowOffset 

But seems like it's not possible... not sure if thats something wrong on the syntax because its
import kind module.symbol name

Its that possible to do?

I suspect that's not an intended use case. One of the things that the import import-kind declaration does is disambiguation; in case there are two identically named declarations coming from different imported modules, the one explicitly imported using import import-kind will be preferred.

However, with a non-top-level declaration like UIKit.UILabel.shadowOffset, such an ambiguity is unlikely to arise in practice.

You could solve the same issue with let shadowOffset = UIKit.UILabel.shadowOffset though.

1 Like

Hey @Varun_Gandh, thanks for the answer :))

Yes, that exactly our case, we have an open-source library that declares a public extension on UIView named shadowOffset: CGSize so users in installing our module get an ambiguous when using it in UILabel, as you mentioned when explicit importing both UIKit and SwifterSwift ... so my idea was to use declaration imports to disambiguate and choose one of them. Here is our issue with more details https://github.com/SwifterSwift/SwifterSwift/issues/622 :)

This seems to give an error where this member is only allowed to be used on an instance of UILabel
Instance member 'shadowOffset' cannot be used on type 'UILabel'; did you mean to use a value of this type instead?

I'm using Swift 5.3 Xcode 12 Beta 1

Sorry, I mistakenly thought it was a static property, but it is an instance property. Hmm, yeah this is kind of unfortunate.

IMO adding a new property with a non-colliding name would be the best way because that also makes it easier for a reader to understand whether the one on UILabel is being used or the one on UIView is being used.

1 Like

This is a known issue with name lookup in Swift. I believe the most recent discussion about a fully-qualified name syntax was here, which would allow you to write something like myLabel.SwiftierSwift::shadowOffset or myLabel.UIKit::shadowOffset to pick out the desired property unambiguously (the precise syntax, as you can read in that thread, is highly debated :slightly_smiling_face:).

2 Likes

Scoped imports (imports targeting a particular declaration) are widely misunderstood. Two things you should know about them:

  1. Their primary, intended use is not to import one declaration from the module and leave the others un-imported; it's to resolve an ambiguity between two modules which declare things with identical names. For instance, suppose DatabaseKit and MusicKit both define a type called Record. import struct DatabaseKit.Record ensures that uses of Record in that file will get the type from DatabaseKit, not the one from MusicKit.

  2. This disambiguation only works for top-level declarations—nested declarations are looked up differently and scoped imports couldn't adjust which one you saw if there was a conflict—so that's the only thing scoped imports support. In other words, import class UIKit.UILabel is valid, but import var UIKit.UILabel.shadowOffset is not.

5 Likes

Thank you for the answers @Varun_Gandhi @Jumhyn @brentdax!

Terms of Service

Privacy Policy

Cookie Policy