[swift-evolution] Proposal: Split extensions into implementing methods and adding static functions Was: [swift-evolution-announce] [Review] SE-0164: Remove final support in protocol extensions

Howard Lovatt howard.lovatt at gmail.com
Wed Apr 19 21:40:32 CDT 2017


As it stands at the moment splitting to multiple files doesn't work. EG:

ModuleA

A.swift

public protocol P {

func m() -> String

}

extension Int: P {

public func m() -> String {

return "AP.m"

}

}

ModuleB

B.swift

public protocol P {

func m() -> String

}
extension Int: P {

public func m() -> String {

return "BP.m"

}

}

ModuleC

A.swift

import ModuleA


func am(_ i: Int) -> String { return i.m() }

B.swift

import ModuleB


func bm(_ i: Int) -> String { return i.m() }

main.swift

let i = 0

print(am(i))
print(bm(i))


Gives the following errors when built:

sunzero-ln:ModuleC lov080$ swift build
Fetching /Users/lov080/Google Drive/Swift/Examples/Example Module
Clashes/ModuleA
Fetching /Users/lov080/Google Drive/Swift/Examples/Example Module
Clashes/ModuleB
Cloning /Users/lov080/Google Drive/Swift/Examples/Example Module
Clashes/ModuleA
Resolving /Users/lov080/Google Drive/Swift/Examples/Example Module
Clashes/ModuleA at 1.0.0
Cloning /Users/lov080/Google Drive/Swift/Examples/Example Module
Clashes/ModuleB
Resolving /Users/lov080/Google Drive/Swift/Examples/Example Module
Clashes/ModuleB at 1.0.0
Compile Swift Module 'ModuleB' (1 sources)
Compile Swift Module 'ModuleA' (1 sources)
Compile Swift Module 'ModuleC' (3 sources)
/Users/lov080/Google Drive/Swift/Examples/Example Module
Clashes/ModuleC/Sources/B.swift:3:38: error: ambiguous use of 'm()'
func bm(_ i: Int) -> String { return i.m() }
                                     ^
ModuleA.Int:2:17: note: found this candidate
    public func m() -> String
                ^
ModuleB.Int:2:17: note: found this candidate
    public func m() -> String
                ^
/Users/lov080/Google Drive/Swift/Examples/Example Module
Clashes/ModuleC/Sources/A.swift:3:38: error: ambiguous use of 'm()'
func am(_ i: Int) -> String { return i.m() }
                                     ^
ModuleA.Int:2:17: note: found this candidate
    public func m() -> String
                ^
ModuleB.Int:2:17: note: found this candidate
    public func m() -> String
                ^
<unknown>:0: error: build had 1 command failures
error: exit(1):
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-build-tool
-f /Users/lov080/Google\ Drive/Swift/Examples/Example\ Module\
Clashes/ModuleC/.build/debug.yaml

As you can see that despite each file A and B in ModuleC only importing one
module each all the extensions apply even if not explicitly imported.

  -- Howard.

On 18 April 2017 at 11:47, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:

> Simple: you put the user code that needs the more accurate library in one
> file and import only the more accurate library there, and you put the user
> code that needs the more performant library in a separate file and import
> only the more performant library there! Swift's devotion to file-based
> organization presents endless avenues of flexibility!
>
> What you write is an argument for designing a more expressive import
> and/or disambiguation feature, not for disallowing public retroactive
> conformance. A proposal to rip out entirely the ability to vend public APIs
> with extensions is simply not going to fly. The core team has committed to
> a small standard library and multiple independent core libraries like
> Foundation. This can only work because Foundation can greatly expand the
> API of standard library types through extensions.
>
> Your proposal would undo that design decision and require folding
> Foundation's functionality into the standard library, or rewriting the
> entire Foundation overlay to encapsulate standard library types instead of
> extending them. For example, NSString would have to be a separate type that
> encapsulates String. Yet oodles of work have gone into making NSString
> seamlessly bridge to String in the first place.
> On Mon, Apr 17, 2017 at 20:05 Howard Lovatt <howard.lovatt at gmail.com>
> wrote:
>
>> Comments in-line below
>>
>> -- Howard.
>>
>> On 17 Apr 2017, at 9:01 am, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>
>> This continues to forbid use cases that are critical.
>>
>>
>> I think "critical" is overstating the importance. Plenty of successful
>> languages do not have extensions. Extensions have been discussed and
>> rejected by successful languages. The .NET guidelines suggest considered
>> cautious use. I have tried to encapsulate the best practice into a language
>> feature.
>>
>>
>> For instance, I am writing a library that vends additional conformances
>> for Float and Double. Any numerics library would need to do the same.
>>
>>
>> You need to consider this carefully because your numerics library might
>> add a method sinh for example and the user of your library might be using
>> other numerical libraries as well, one of these others might also provide
>> sinh. Which is to be called in the user code by f.sinh? Suppose one library
>> emphasises speed over accuracy and the other vice versa. You really want
>> access to both versions in the user code. This is a situation I have come
>> across a few times in numeric C, Java, and C++ with matrix libraries where
>> code I have worked on has used multiple libraries in the same application
>> for good reason.
>>
>> I think you would be better vending functions for things like sinh,
>> rather than extending float with an additional function, and vending types
>> for more complex things like matrices, rather than extending arrays with
>> dot products for example. If you vend a type you can easily give access to
>> the underlying type using composition rather than extension or inheritance,
>> there is an example of this in the proposal just above the Justification
>> section..
>>
>>
>> Your design would eliminate all such libraries, which is a non-starter. I
>> am not sure what defects you are trying to solve with this proposal.
>>
>> I am trying to make Swift more consistent, easier to learn, and to
>> encourage third-party libraries.
>>
>>
>> On Sun, Apr 16, 2017 at 17:51 Howard Lovatt <howard.lovatt at gmail.com>
>> wrote:
>>
>>> @Brent,
>>>
>>> I have updated the proposal to address your concerns, in particular I
>>> don't see that retrospectively adding methods and protocols has been
>>> removed it has just had its ugly corners rounded. See revised proposal
>>> below particularly the end of section "Retrospectively adding protocols
>>> and methods" and new section "Justification".
>>>
>>> Hope this convinces you that the change is worthwhile.
>>>
>>> -- Howard.
>>>
>>> ====================================
>>>
>>> # Proposal: Split extension usage up into implementing methods and
>>> adding methods and protocols retrospectively
>>>
>>>
>>> ## Revision history
>>>
>>> | Version | Date               | Comment       |
>>>
>>> |---------|--------------|--------------|
>>>
>>> | Draft 1   | 11 April 2017 | Initial version |
>>>
>>> | Draft 2  | 13 April 2017 | Added support for post-hoc conformance to a
>>> protocol - replaced static final extensions with final extensions |
>>>
>>> | Draft 3 | 17 April 2017 | Added justification section |
>>>
>>>
>>> ## Introduction
>>>
>>>
>>> Currently extension methods are confusing because they have different
>>> dispatch rules for the same calling syntax. EG:
>>>
>>>
>>>     public protocol P {
>>>
>>>         func mP() -> String
>>>
>>>      }
>>>
>>>     extension P {
>>>
>>>         func mP() -> String { return "P.mP" }
>>>
>>>         func mE() -> String { return "P.mE" }
>>>
>>>     }
>>>
>>>     struct S: P {
>>>
>>>         func mP() -> String { return "S.mP" }
>>>
>>>         func mE() -> String { return "S.mE" }
>>>
>>>     }
>>>
>>>     let s = S()
>>>
>>>     s.mP() // S.mP as expected
>>>
>>>     s.mE() // S.mE as expected
>>>
>>>     let p: P = s // Note: s now typed as P
>>>
>>>     p.mP() // S.mP as expected
>>>
>>>     p.mE() // P.mE unexpected!
>>>
>>>
>>> Extension methods can also cause compatibility problems between modules,
>>> consider:
>>>
>>>
>>> In Module A
>>>
>>>     extension Int: P {
>>>
>>>         func m() -> String { print("A.m") }
>>>
>>>     }
>>>
>>>
>>> In Module B
>>>
>>>     extension Int: P {
>>>
>>>         func m() -> String { print("B.m") }
>>>
>>>     }
>>>
>>>
>>> In Module C
>>>
>>>     import A
>>>
>>>     import B // Should this be an error
>>>
>>>     let i = 0
>>>
>>>     i.m() // Should it return A.m or B.m?
>>>
>>>
>>> This proposal cures the above two problems by separating extension
>>> methods into two seperate use cases: implementations for methods and adding
>>> methods and protocols retrospectively.
>>>
>>>
>>> ## Implementing methods
>>>
>>>
>>> If the extension is in the same file as the protocol/struct/enum/class
>>> declaration then it implements the methods and is dispatched using a
>>> Vtable. EG:
>>>
>>>
>>> File P.swift
>>>
>>>     protocol/struct/enum/class P {
>>>
>>>         // func m() not declared in type since it is added by the
>>> extension, under this proposal it is an error to include a declaration in a
>>> type *and* in an extension
>>>
>>>     }
>>>
>>>     extension P {
>>>
>>>         func m() { print("P.m") } // m is added to the
>>> protocol/struct/enum/class declaration
>>>
>>>     }
>>>
>>>
>>> Same or other file
>>>
>>>     struct S: P {
>>>
>>>         override func m() { print("S.m") } // Note override required
>>> because m already has an implementation from the extension
>>>
>>>     }
>>>
>>>     let p: P = S() // Note typed as P
>>>
>>>     p.m() // Now prints S.m as expected
>>>
>>>
>>> Extensions in the same file as the declaration can have any access, can
>>> be final, and can have where clauses and provide inheritable
>>> implementations.
>>>
>>>
>>> In a protocol at present there is a difference in behaviour between a
>>> protocol that declares a method that is then implemented in an extension
>>> and a protocol that just has the method implemented in an extension and no
>>> declaration. This situation only applies to protocols, for
>>> structs/enumerated/classes you cannot declare in type and implement in
>>> extensions. The proposal unifies the behaviour of
>>> protocol/struct/enum/class with extensions and prevents the error of a
>>> minor typo between the protocol and extension adding two methods instead of
>>> generating an error.
>>>
>>>
>>> The implementation needed to achieve this proposal is that a value
>>> instance typed as a protocol is copied onto the heap, a pointer to its
>>> Vtable added, and it is passed as a pointer. IE it becomes a class
>>> instance. No change needed for a class instance typed as a protocol.
>>>
>>>
>>> ## Retrospectively adding protocols and methods
>>>
>>>
>>> A new type of extension is proposed, a "final extension", which can be
>>> either in or outside the file in which the protocol/struct/enum/class
>>> declaration is in. EG:
>>>
>>>
>>>     protocol P2 {
>>>
>>>         func m2P()
>>>
>>>     }
>>>
>>>     final extension S: P2 { // Note extension marked final
>>>
>>>         func m2P() { print("SP2.m2P") } // Implicitly final, completely
>>> implements P2
>>>
>>>         func m2E() { print("SP2.m2E") } // Implicitly final, not an
>>> existing method
>>>
>>>     }
>>>
>>>
>>> Which are called as any other method would be called:
>>>
>>>
>>>     let s = S()
>>>
>>>     s.m2P() // Prints SP2.m2P
>>>
>>>     s.m2E() // Prints SP2.m2E
>>>
>>>
>>> A method added by a final extension is is implicitly final, as the name
>>> would suggest, and cannot be overridden.
>>>
>>>
>>> Notes:
>>>
>>>
>>>   1. If the final extension adds a method, e.g. m2E, that method cannot
>>> already exist. IE a final extension cannot override an existing method or
>>> implement a protocol declared method that lacks an implementation unless it
>>> also adds the protocol.
>>>
>>>
>>>   2. If the final extension adds a protocol then it must implement all
>>> the methods in that protocol that are not currently implemented.
>>>
>>>
>>>   3. If the final extension is outside of the file in which the
>>> protocol/struct/enum/class declaration is in then the extension and the
>>> methods can only have fileprivate or internal access. This prevents
>>> retrospective extensions from numerous modules clashing, since they are not
>>> exported outside of the module.
>>>
>>>
>>> When a type is extended inside a module with a final extension the
>>> extension is not exported. For example:
>>>
>>>
>>>     final extension Int: P2 {
>>>
>>>         func m2P() { print("Int.m2P") }
>>>
>>>     }
>>>
>>>
>>> If an exported function uses Int, e.g.:
>>>
>>>
>>>     public func f(_ x: Int) -> Int {
>>>
>>>         x.m2P()
>>>
>>>         return x
>>>
>>>     }
>>>
>>>
>>> Then when used in an external module both the input Int and the output
>>> Int are not extended with P2. However as the Int goes into f it gains P2
>>> conformance and when it leaves it looses P2 conformance. Thus inside and
>>> outside the module the behaviour is easily understood and consistent and
>>> doesn't clash with other final extensions in other modules.
>>>
>>>
>>> Taking the above example further an Int with P2 conformance is required
>>> by the user of a library; then it can simply and safely be provided, e.g.:
>>>
>>>
>>>     public class P2Int: P2 {
>>>
>>>         var value = 0
>>>
>>>         func m2P() { print("Int.m2P") }
>>>
>>>     }
>>>
>>>
>>> This type, P2Int, is easy to write, one line longer than a final
>>> extension, and can easily be used as both a P2 and an Int and does not
>>> clash with another Int extension from another module.
>>>
>>>
>>> ## Justification
>>>
>>>
>>> The aim of Swift is nothing more than dominating the world. Using the
>>> current, April 2017, https://www.tiobe.com/tiobe-index/ index of job
>>> adverts for programmers the languages that are in demand are: Java 15.568%,
>>> C 6.966%, C++ 4.554%, C# 3.579%, Python 3.457%, PHP 3.376%, Visual Basic
>>> .NET 3.251%, JavaScript 2.851%, Delphi/Object Pascal 2.816%, Perl 2.413%,
>>> Ruby 2.310%, and Swift 2.287%. So Swift at 12th is doing very well for a
>>> new language and is already above Objective-C at 14th. However there is
>>> obviously a long way to go and the purpose of this proposal is to help with
>>> this climb.
>>>
>>>
>>> A characteristic of many of the languages above Swift in the Tiobe Index
>>> is that they have major third party libraries; for some languages they are
>>> almost defined by their third part libraries, e.g. Ruby for Rails. A major
>>> part of this proposal is to make extensions safe when using multiple
>>> libraries from different venders. In particular final extensions are not
>>> exported.
>>>
>>>
>>> As part of Swift's goal of world domination is that it is meant to be
>>> easy to learn by a process of "successive disclosure". The current
>>> inconsistent behaviour of protocols and extensions hinders this process and
>>> is a common gotcha for newbies. This proposal eliminates that problem also.
>>>
>>>
>>> Extensions are not new in languages, they are part of the .NET languages
>>> for example. Since .NET popularised extensions they have been discussed by
>>> other language communities, particularly Java and Scala, and in the
>>> academic community (normally termed the Expression Problem) however they
>>> have not proved popular because of the problems they cause. Nearly all
>>> languages have a strong bias towards keeping the language small and simple
>>> and trade of the advantages of a feature against the disadvantages and the
>>> feature only makes it into the language if it offers many advantages, has
>>> few disadvantages, and is not heavily overlapping with other features. This
>>> keeping it small and simple test is what extensions have failed in other
>>> languages.
>>>
>>>
>>> Experience from .NET can however be used to improve extensions. There is
>>> some excellent advice https://blogs.msdn.microsoft.
>>> com/vbteam/2007/03/10/extension-methods-best-
>>> practices-extension-methods-part-6/ written by the VB .NET team when
>>> they added extensions to VB .NET. The best-practice advice can be
>>> summarised by the following quotes from the reference:
>>>
>>>
>>>   0. "In most real world applications these suggestions [the rest of the
>>> suggestions] can (and quite frankly should!) be completely ignored." This
>>> is an important observations, in your own code that is not intended for
>>> reuse; go for it, use extensions. The proposal importantly still allows
>>> this style of programming and in fact improves it by adding consistent
>>> behaviour and syntax between protocols/structs/enumerated/classes.
>>>
>>>
>>>  1. "Read the .NET Framework Class Library Design Guidelines." The
>>> equivalent for Swift is lacking at this stage. Probably because third party
>>> libraries are rare.
>>>
>>>
>>>   2. "Be wary of extension methods." This recommendation is formalised
>>> in the proposal by limiting final extensions to be fileprivate or internal.
>>>
>>>
>>>   3. "Put extension methods into their own namespace." This
>>> recommendation is formalised in the proposal by limiting final extensions
>>> to be fileprivate or internal.
>>>
>>>
>>>   4. "Think twice before extending types you don’t own."
>>>
>>>
>>>   5. "Prefer interface extensions over class extensions." Translation to
>>> Swift terminology provide default implementations for protocol methods. The
>>> proposal encourages this by eliminating a major gotcha with the current
>>> implementation, namely the proposal always dispatches via a Vtable to give
>>> consistent behaviour.
>>>
>>>
>>>   6. "Be as specific with the types you extend as possible." Translation
>>> to Swift terminology provide default implementations for protocol methods
>>> that extend other  protocols if there is a more specific behaviour that is
>>> relevent. The proposal encourages this by eliminating a major gotcha with
>>> the current implementation, namely the proposal always dispatches via a
>>> Vtable to give consistent behaviour.
>>>
>>>
>>> The proposal formalises these best practices from .NET whilst increasing
>>> consistence and without loosing the ability to use extensions heavily in
>>> your own one-off code to allow for rapid development. Most of the best
>>> practices are for better libraries, particularly third party, which is an
>>> important area for future Swift growth onto the server side. This proposal
>>> actively encourages this transition to large formal server side code
>>> without loosing the free wheeling nature of app code.
>>>
>>>
>>> ## Possible future work (not part of this proposal)
>>>
>>>
>>> This proposal will naturally allow bodies to be added to protocols
>>> directly rather than via an extension, since under the proposal the
>>> extension adds the declaration to the type so it is a small step to allow
>>> the protocol methods to have an implementation.
>>>
>>>
>>> In an opposite sense to the above adding bodies to protocols, extensions
>>> could be allowed to add method declarations without bodies to protocols.
>>>
>>>
>>> The two above future work proposals, if both added, would add symmetry
>>> to where declarations and bodies may appear for protocols.
>>>
>>>
>>> ## In summary.
>>>
>>>
>>> The proposal formalises the split use of extensions into their two uses:
>>> implementing methods and post-hoc adding protocols and methods. Syntax is
>>> added that clarifies the two use cases, the former are termed extensions
>>> and must be in the same file as the type is declared, and the latter are
>>> termed final extensions and can be in any file, however if they are not in
>>> the type's file the they can only have fileprivate or internal access.
>>>
>>>
>>> Note the distinction between an extension in the same file and in a
>>> separate file is consistent with the philosophy that there is special
>>> status to the same file as proposed for private in
>>> https://github.com/apple/swift-evolution/blob/master/
>>> proposals/0169-improve-interaction-between-private-
>>> declarations-and-extensions.md.
>>>
>>>
>>> ===================================================
>>>
>>>
>>> #Proposal: Split extension usage up into implementing methods and adding
>>> methods and protocols post-hoc
>>>
>>>
>>> Draft 2 (Added support for post-hoc conformance to a protocol - replaced
>>> static final extensions with final extensions)
>>>
>>>
>>> ## Introduction
>>>
>>>
>>> Currently extension methods are confusing because they have different
>>> dispatch rules for the same calling syntax. EG:
>>>
>>>
>>>     public protocol P {
>>>
>>>         func mP() -> String
>>>
>>>      }
>>>
>>>     extension P {
>>>
>>>         func mP() -> String { return "P.mP" }
>>>
>>>         func mE() -> String { return "P.mE" }
>>>
>>>     }
>>>
>>>     struct S: P {
>>>
>>>         func mP() -> String { return "S.mP" }
>>>
>>>         func mE() -> String { return "S.mE" }
>>>
>>>     }
>>>
>>>     let s = S()
>>>
>>>     s.mP() // S.mP as expected
>>>
>>>     s.mE() // S.mE as expected
>>>
>>>     let p: P = s // Note: s now typed as P
>>>
>>>     p.mP() // S.mP as expected
>>>
>>>     p.mE() // P.mE unexpected!
>>>
>>>
>>> Extension methods can also cause compatibility problems between modules,
>>> consider:
>>>
>>>
>>> In Module A
>>>
>>>     extension Int: P {
>>>
>>>         func m() -> String { print("A.m") }
>>>
>>>     }
>>>
>>>
>>> In Module B
>>>
>>>     extension Int: P {
>>>
>>>         func m() -> String { print("B.m") }
>>>
>>>     }
>>>
>>>
>>> In Module C
>>>
>>>     import A
>>>
>>>     import B // Should this be an error
>>>
>>>     let i = 0
>>>
>>>     i.m() // Should it return A.m or B.m?
>>>
>>>
>>> This proposal cures the above two problems by separating extension
>>> methods into two seperate use cases: implementations for methods and adding
>>> methods and protocols post-hoc.
>>>
>>>
>>> ## Implementing methods
>>>
>>>
>>> If the extension is in the same file as the protocol/struct/class
>>> declaration then it implements the methods and is dispatched using a
>>> Vtable. EG:
>>>
>>>
>>> File P.swift
>>>
>>>     protocol/struct/class P {
>>>
>>>         // func m() not declared in type since it is added by the
>>> extension, under this proposal it is an error to include a declaration in a
>>> type *and* in an extension
>>>
>>>     }
>>>
>>>     extension P {
>>>
>>>         func m() { print("P.m") } // m is added to the
>>> protocol/struct/class declaration
>>>
>>>     }
>>>
>>>
>>> Same or other file
>>>
>>>     struct S: P {
>>>
>>>         override func m() { print("S.m") } // Note override required
>>> because m already has an implementation from the extension
>>>
>>>     }
>>>
>>>     let p: P = S() // Note typed as P
>>>
>>>     p.m() // Now prints S.m as expected
>>>
>>>
>>> Extensions in the same file as the declaration can have any access, can
>>> be final, and can have where clauses and provide inheritable
>>> implementations.
>>>
>>>
>>> In a protocol at present there is a difference in behaviour between a
>>> protocol that declares a method that is then implemented in an extension
>>> and a protocol that just has the method implemented in an extension and no
>>> declaration. This situation only applies to protocols, for structs and
>>> classes you cannot declare in type and implement in extensions. The
>>> proposal unifies the behaviour of protocol/struct/class with extensions and
>>> prevents the error of a minor typo between the protocol and extension
>>> adding two methods instead of generating an error.
>>>
>>>
>>> The implementation needed to achieve this is that a value instance typed
>>> as a protocol is copied onto the heap, a pointer to its Vtable added, and
>>> it is passed as a pointer. IE it becomes a class instance. No change needed
>>> for a class instance typed as a protocol.
>>>
>>>
>>> ## Post-hoc adding protocols and methods
>>>
>>>
>>> A new type of extension is proposed, a "final extension", which can be
>>> either in or outside the file in which the protocol/struct/class
>>> declaration is in. EG:
>>>
>>>
>>>     protocol P2 {
>>>
>>>         func m2P()
>>>
>>>     }
>>>
>>>     final extension S: P2 { // Note extension marked final
>>>
>>>         func m2P() { print("SP2.m2P") } // Implicitly final, completely
>>> implements P2
>>>
>>>         func m2E() { print("SP2.m2E") } // Implicitly final, not an
>>> existing method
>>>
>>>     }
>>>
>>>
>>> Which are called as any other method would be called:
>>>
>>>
>>>     let s = S()
>>>
>>>     s.m2P() // Prints SP2.m2P
>>>
>>>     s.m2E() // Prints SP2.m2E
>>>
>>>
>>> A method added by a final extension is is implicitly final, as the name
>>> would suggest, and cannot be overridden.
>>>
>>>
>>> If the final extension:
>>>
>>>
>>>   1. Adds a method, e.g. m2E, that method cannot already exist. IE a
>>> final extension cannot override an existing method or implement a protocol
>>> declared method that lacks an implementation unless it also post-hoc adds
>>> the protocol.
>>>
>>>
>>>   2. Adds a protocol then it must implement all the methods in that
>>> protocol that are not currently implemented.
>>>
>>>
>>>   3. Is outside of the file in which the protocol/struct/class
>>> declaration is in then the extension and the methods can only have
>>> fileprivate or internal access. This prevents post-hoc extensions from
>>> numerous modules clashing, since they are not exported outside of the
>>> module.
>>>
>>>
>>> ## Possible future work (not part of this proposal)
>>>
>>>
>>> This proposal will naturally allow bodies to be added to protocols
>>> directly rather than via an extension, since under the proposal the
>>> extension adds the declaration to the type so it is a small step to allow
>>> the protocol methods to have an implementation.
>>>
>>>
>>> In an opposite sense to the above adding bodies to protocols, extensions
>>> could be allowed to add method declarations without bodies to protocols.
>>>
>>>
>>> The two above future work proposals, if both added, would add symmetry
>>> to where declarations and bodies may appear for protocols.
>>>
>>>
>>> ## In summary.
>>>
>>>
>>> The proposal formalises the split use of extensions into their two uses:
>>> implementing methods and post-hoc adding protocols and methods. Syntax is
>>> added that clarifies the two use cases, the former are termed extensions
>>> and must be in the same file as the type is declared, and the latter are
>>> termed final extensions and can be in any file, however if they are not in
>>> the type's file the they can only have fileprivate or internal access.
>>>
>>>
>>> Note the distinction between an extension in the same file and in a
>>> separate file is consistent with the philosophy that there is special
>>> status to the same file as proposed for private in
>>> https://github.com/apple/swift-evolution/blob/master/
>>> proposals/0169-improve-interaction-between-private-
>>> declarations-and-extensions.md.
>>>
>>>
>>> ====================================
>>>
>>> On 14 Apr 2017, at 8:17 am, Brent Royal-Gordon <brent at architechies.com>
>>> wrote:
>>>
>>> On Apr 13, 2017, at 3:10 PM, Howard Lovatt via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>
>>> I don't see that retroactive conformance needs to be exportable. If it
>>> is exported then you cannot prevent clashes from two modules, this is a
>>> known problem in C#. Because of this and other problems with C# extensions,
>>> this style of extension were rejected by other language communities
>>> (notably Java and Scala).
>>>
>>>
>>> A better alternative for export is a new class that encapsulates the
>>> standard type but with added methods for the protocol to be added. This way
>>> there is no clash between modules. EG:
>>>
>>>
>>>    public protocol P {
>>>
>>>        func m() -> String
>>>
>>>    }
>>>
>>>    public class PInt: P {
>>>
>>>        var value = 0
>>>
>>>        func m() -> String { return "PI.m" }
>>>
>>>    }
>>>
>>>
>>> Howard, this would be very source-breaking and would fail to achieve
>>> fundamental goals of Swift's protocol design. Removing retroactive
>>> conformance is no more realistic than removing Objective-C bridging—another
>>> feature which introduces various ugly edge cases and tricky behaviors but
>>> is also non-negotiable.
>>>
>>> --
>>> Brent Royal-Gordon
>>> Architechies
>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170420/d5a8ffa1/attachment.html>


More information about the swift-evolution mailing list