[swift-evolution] [Pitch] [Phase 2] New `permuting` keyword for protocols

Xiaodi Wu xiaodi.wu at gmail.com
Mon Dec 26 04:50:38 CST 2016


Given `foo: T` and methods a(), b(), c(), d(), each of which can only be
called once, how can the return value of these methods be represented in
the type system?

That is, if `foo.a()` can be passed as an argument to an arbitrary function
of type `(T) -> U`, either the function cannot immediately invoke a(), in
which case foo is not of type T, or it can immediately invoke a(), in which
case your keyword does not work.

On Mon, Dec 26, 2016 at 04:32 Adrian Zubarev via swift-evolution <
swift-evolution at swift.org> wrote:

> Hi Swift community,
>
> I’d like you to think about the idea of being able to create protocols
> with a permutation path.
>
> Recently I build a really tiny wrapper API around NSLayoutAnchor, where I
> wanted the user to have a nice and shiny API. The user can decide with
> which method he starts and optionally chain the other methods after that.
> The main restriction was that each method could only be used once, which is
> what a permutation offers. For that project I had to model and overload
> over 30 protocols, which overlaps only 5 different methods. If I had to add
> more methods, the permutation protocol model would silly explode.
>
> You can look up a visual graph here:
> https://github.com/DevAndArtist/swift-functionallayout
>
> My pitch is purely additive and could be considered during phase 2!
>
> Similar to indirect the new keyword would be applied to protocol members
> or to the protocol itself.
>
> protocol Foo {
>       permuting mutating func foo() -> Foo
>       permuting mutating func boo() -> Foo
>       permuting mutating func zoo() -> Foo
>
>       func bar() -> EscapingType
>
>       var x: Foo { get } // returns a new permutation path
> }
>
> permuting protocol Boo {
>       func a() -> Boo
>       func b() -> Boo
>
>       func c() -> EscapingType
>
>       var x: Boo { get } // participates in the current permutation chain
> }
>
> Example with Foo:
>
> class A : Foo {
>     permuting mutating func foo() -> Foo { return self }
>     permuting mutating func boo() -> Foo { return self }
>
>     func bar() -> EscapingType { return … }
>
>     var x: Foo { return self }
> }
>
> let a = A().foo()
>
> a.
> // From here only the following part of `Foo` would be visible
> //
> // func boo() -> Foo
> // func zoo() -> Foo
> // func bar() -> EscapingType
> // var x: Foo { get }
> //
> // `foo` is not visible because it's already used in the current permutation chain
> //
>
> let aa = a.zoo()
>
> //
> // Visible API from `aa`
> //
> // func boo() -> Foo
> // func bar() -> EscapingType
> // var x: Foo { get }
> //
>
> aa.x.
>
> //
> // Since `x` is not marked with `permuting` keyword, it returns a new permutation chain where the whole `Foo` interface is again visible
> //
>
> aa.x.bar() // this will escape the permutation chain completely, because we're not returning `Foo` interface here
>
> Only a chain of members that returning the same protocol (or even Self?)
> and are marked with the permuting keyword are considered as part of the
> same permutation.
>
> Members that are not permuting will either escape the permutation chain
> or create a new one, like bar or x in the example above.
> ------------------------------
>
> Personally I think that would be a really handy tool for neat API design.
> It also helps to restrict some functional design while ease the build
> complexity.
>
> My small wrapper API could be reduced to 3 protocols.
>
>
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161226/bbeaa3d4/attachment.html>


More information about the swift-evolution mailing list