Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will marking swift extension public change the property in the extension to be implicitly public or internal?

Tags:

ios

swift

So in Apple documentation:

Any type members added in an extension have the same default access level as type members declared in the original type being extended. If you extend a public or internal type, any new type members you add will have a default access level of internal.

Giving a sub class of UIView extension:

extension UIViewSubClass
{
    var helloWorld : String {
        get {
            return "helloWorld"
        }
    }
}

This will mark helloWorld as internal, I have no problem, and I cannot see it in my Objective-C based project.

However, if I mark the extension to be public:

public extension UIViewSubClass
{
    var helloWorld : String {
        get {
            return "helloWorld"
        }
    }
}

Now helloWorld apprears in my Objective-C based code, which means it is marked as public.

However, I don't see Apple mentions this, did it?

I just saw the documentation said a public class will still has implicit internal level.

public class SomePublicClass {          // explicitly public class
    public var somePublicProperty = 0    // explicitly public class member
    var someInternalProperty = 0         // implicitly internal class member
    private func somePrivateMethod() {}  // explicitly private class member
}

Marking public for extension seems have different effect than marking a Class definition. This makes me confused.

Could someone help me, is this supposed to be so, or this is a sort of swift bug? I am with swift 2.1 and Xcode 7.2

like image 977
Wingzero Avatar asked Dec 26 '15 10:12

Wingzero


People also ask

Can we declare property in extension in Swift?

Extensions can add new computed properties, but they can't add stored properties, or add property observers to existing properties.

What kind of properties can a Swift extension have?

Computed Property In Extension However, Swift lets us add computed properties to an extension. For example, extension Circle { // computed property var area: Double { ... } } Here, area is a computed property defined in the extension body.

What is the point of extension Swift?

A Swift extension allows you to add functionality to a type, a class, a struct, an enum, or a protocol.

How do I override a Swift extension?

It is not possible to override functionality (like properties or methods) in extensions as documented in Apple's Swift Guide. Extensions can add new functionality to a type, but they cannot override existing functionality. The compiler is allowing you to override in the extension for compatibility with Objective-C.


1 Answers

Answer: Yes, placing access level modifiers (in your case, public, specifically) in front of extensions modify the default access level of all new types in the scope of that extension.

Note that the modifier does not affect the access level of the class/struct/etc being extended (only it's members. However, there are things that ought to be considered, as I will discuss below.


In this discussion, I'll post a few important facts regarding regarding access levels in Swift. All these are from the Swift Language Guide - Access Control - Access Levels.

Let's first assure what you've already stated:

All entities in your code (with a few specific exceptions, as described later in this chapter) have a default access level of internal if you do not specify an explicit access level yourself.

OK, this goes in line with what you've quoted in you question: any new type members, whether in a class or structure definition, will have a default access level of internal.

Now, lets look at the access level modifier that you can add in front of extensions:

You can extend a class, structure, or enumeration in any access context in which the class, structure, or enumeration is available. Any type members added in an extension have the same default access level as type members declared in the original type being extended. If you extend a public or internal type, any new type members you add will have a default access level of internal. If you extend a private type, any new type members you add will have a default access level of private.

Alternatively, you can mark an extension with an explicit access level modifier (for example, private extension) to set a new default access level for all members defined within the extension. This new default can still be overridden within the extension for individual type members.

This sorts things out. We look at your example, and assume that your class UIViewSubClass has access level public (or compile time error, se below):

/* no access level modifier: default access level will be 'internal' */
extension UIViewSubClass
{
    // default access level used: internal
    var helloWorld : String { 
        get {
            return "helloWorld"
        }
    }
}

// modify default access level to public
public extension UIViewSubClass
{
    // default access level used: public
    var helloWorld : String { 
        get {
            return "helloWorld"
        }
    }
}

With the discussion above in mind, it's expected that your helloWorld in you public extension ... is marked as internal, as this is, in this context, the default access level. In the context of extensions, access level modifiers work differently than when applied to types.

Finally, we should point out that using a public access modifier when extending a non-public class will yield a compile time error in Swift. So in your case above:

  • If UISubViewClass is an internal or a private class, then the public extension ... on the class will yield an compile time error.
  • If UISubViewClass is a public class, then adding the public extension will be redundant as the default access modifier of a public class is already, by definition, public.

I'd say that the error described above is not really an error to avoid runtime errors, but rather to avoid redundant (and confusing) code: public member types or private or internal classes will never make use of itspublic` access level.

class MyImplicitlyInternalClass {
    private var myExplicitlyPrivateVar = 0
    var myImplicitlyInternalVar = 0
    public var myExplicitlyPublicVar = 0 // warning, see (Note 1) below
        // redundant 'public': can never be accessed publicly
        // myExplicitlyPublicVar will behave as 'internal'
}

public extension MyImplicitlyInternalClass { // error, see (Note 2)
    var myNewVarIsInternal : Int { get { return 0 } } 
}
/* (Note 1) Compile type warning:
        "Declaring a public var for an internal class."

   (Note 2) Compile time error:
        "Extension of internal class cannot be declared public." 

   Summary: in theory, these two above are the same type of
            'faults', but only the latter is flagged as and error. */

Hence, it only ever makes sense to use the access level modifiers on extensions to make the default access level more restrictive, i.e., using internal extension ... of a public class, or private extension or an internal class.

like image 59
dfrib Avatar answered Oct 05 '22 23:10

dfrib