I’ve spotted some inconsistency on access control modifier I’d like to discuss 
in this thread (the behavior is not groundbreaking but inconsistent from 
readers and developers view perspective).

Why are extensions not marked as public in public apis when the module is 
imported?

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.

Source: Apple Inc. The Swift Programming Language (Swift 2.2).
This does not tell us how the access control modifier works on extensions. Here 
are three examples:
public struct A {}
     
/* implicitly internal */ extension A {}
     
// This extension won't be exported
as soon as at least one member modifier of an extension is public (if the 
extended type allows that and is also public), the extension itself becomes 
implicitly public:
public struct B {}
     
/* implicitly public */ extension B {
         
    public func foo() {}     
         
    /* implicitly internal */ func boo() {}
}
     
// This extension will be exported as
     
extension B {
         
    public func foo()
}
This is inconsistent to other types, because you can not leave out the modifier 
for instance on classes, then add a public member and assume that your class is 
implicitly public! The compiler knows that and provides a correct warning that 
the mentioned class is internal.

public struct C {}
     
public extension C {
         
    public func foo() {}     
         
    /* implicitly internal */ func boo() {}
}
     
// This extension will be exported as
     
/* public is missing here */ extension C {
         
    public func foo()
}
Extensions seem to behave differently and its behaviors is inconsistent and not 
documented.

protocols has explicit public modifier on its members when the module is 
imported. However, 'public' modifier cannot be used in protocols is how the 
compiler treat modifiers in protocols on declaration.

public protocol D {
         
    func doSomething()
}
Protocol D will be exported as:

public protocol D {
         
    public func doSomething()
}
Here is my suggestion:

Fix the behavior for extensions and document it correctly:

public struct B {}
     
/* implicitly public */ extension B {
         
    public func foo() {}     
         
    /* implicitly internal */ func boo() {}
}
Such an extension should not be implicitly public and behave like other types 
and stay implicitly internal.
The compiler should provide a warning for the foo() function: Declaring a 
public function for an internal type
Extensions should have explicit public modifier like other types if the 
extension was marked as public and was imported into an other project/module.
This inconsistent behavior is source breaking and I’d suggest this change to 
happen in Swift 3!
Remove public modifier from imported protocols OR document this behavior 
correctly!



-- 
Adrian Zubarev
Sent with Airmail
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to