[Discussion] Here we go again: Extension Functions


#1

I'm reopening a topic that has already been discussed here at length[1]: setup closures and `self`-binding closures.

I've been wondering if Swift could adopt what Kotlin calls "extension function expressions"[2]. These would allow us to encode a closure's receiver type (`self`) into the closure type itself, providing a powerful, type-safe way to define DSLs.

Erica's earlier draft proposed this builder pattern:

    with let task = NSTask() {
        launchPath = "/usr/bin/mdfind"
        arguments = ["kMDItemDisplayName == *.playground"]
        standardOutput = pipe
    }

With extension functions, we could approach something similar:

    func with<T>(value: T, body: T.() -> ()) -> T {
        value.body()
        return value
    }

    let task = with(NSTask()) {
        launchPath = "/usr/bin/mdfind"
        arguments = ["kMDItemDisplayName == *.playground"]
        standardOutput = pipe
    }

Or, using the `then`[3] pattern:

    protocol Builder {}
    extension Builder {
        func then(body: Self.() -> ()) -> Self {
            body()
            return self
        }
    }
    extension NSTask: Builder {}
    
    let task = NSTask().then {
        launchPath = "/usr/bin/mdfind"
        arguments = ["kMDItemDisplayName == *.playground"]
        standardOutput = pipe
    }

How about BDD-style frameworks (like Quick/Nimble[4] and Spectre[5])?

    describe("a person") {
        let person = Person(name: "Kyle")

        it("has a name") {
            try expect(person.name) == "Kyle"
        }
    }

And HTML builders?

    html {
        head { title("Hello, World!") }
    }

And block-based, transactional APIs?

    db.inTransaction {
        delete("users", "first_name = ?", ["Jake"])
    }

The main benefits have been previously discussed:

1. The ability to remove noise ("$0" everywhere)
2. The ability to avoid defining globals (in favor of a safer, scoped interface)

Would such an enhancement be feasible?

···

---
Stephen

Footnotes:

[1] A probably-incomplete list:
- "Idea for enabling DSLs: bind to self in closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000114.html
- "Request for Discussion: Setup closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000211.html
- "Method cascading (was Re: Request for Discussion: Setup closures)": https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151130/000729.html
- "Fluent syntax (replacing void with a useful default return value)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/374
- "Lexical scope statement (with .. do)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1408
- "Scoped resources (like C# using statement)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1641
- "Customized Inline Init Closure": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1946
- "Then Support": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2054
- "Draft proposal: multi-property assignment .= operator": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2960
- "Custom default names for arguments of closures": http://thread.gmane.org/gmane.comp.lang.swift.evolution/6969
- https://bugs.swift.org/browse/SR-160

[2] https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver
[3] https://github.com/devxoul/Then
[4] https://github.com/Quick/Quick
[5] https://github.com/kylef/Spectre


(Erica Sadun) #2

I'm really intrigued to see where this goes. Thanks, Stephen.

-- Erica

···

On Feb 25, 2016, at 3:47 PM, Stephen Celis via swift-evolution <swift-evolution@swift.org> wrote:

I'm reopening a topic that has already been discussed here at length[1]: setup closures and `self`-binding closures.

I've been wondering if Swift could adopt what Kotlin calls "extension function expressions"[2]. These would allow us to encode a closure's receiver type (`self`) into the closure type itself, providing a powerful, type-safe way to define DSLs.

Erica's earlier draft proposed this builder pattern:

   with let task = NSTask() {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

With extension functions, we could approach something similar:

   func with<T>(value: T, body: T.() -> ()) -> T {
       value.body()
       return value
   }

   let task = with(NSTask()) {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

Or, using the `then`[3] pattern:

   protocol Builder {}
   extension Builder {
       func then(body: Self.() -> ()) -> Self {
           body()
           return self
       }
   }
   extension NSTask: Builder {}

   let task = NSTask().then {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

How about BDD-style frameworks (like Quick/Nimble[4] and Spectre[5])?

   describe("a person") {
       let person = Person(name: "Kyle")

       it("has a name") {
           try expect(person.name) == "Kyle"
       }
   }

And HTML builders?

   html {
       head { title("Hello, World!") }
   }

And block-based, transactional APIs?

   db.inTransaction {
       delete("users", "first_name = ?", ["Jake"])
   }

The main benefits have been previously discussed:

1. The ability to remove noise ("$0" everywhere)
2. The ability to avoid defining globals (in favor of a safer, scoped interface)

Would such an enhancement be feasible?

---
Stephen

Footnotes:

[1] A probably-incomplete list:
- "Idea for enabling DSLs: bind to self in closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000114.html
- "Request for Discussion: Setup closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000211.html
- "Method cascading (was Re: Request for Discussion: Setup closures)": https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151130/000729.html
- "Fluent syntax (replacing void with a useful default return value)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/374
- "Lexical scope statement (with .. do)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1408
- "Scoped resources (like C# using statement)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1641
- "Customized Inline Init Closure": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1946
- "Then Support": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2054
- "Draft proposal: multi-property assignment .= operator": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2960
- "Custom default names for arguments of closures": http://thread.gmane.org/gmane.comp.lang.swift.evolution/6969
- https://bugs.swift.org/browse/SR-160

[2] https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver
[3] https://github.com/devxoul/Then
[4] https://github.com/Quick/Quick
[5] https://github.com/kylef/Spectre

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Russ Bishop) #3

+1 to this or something like it.

Right now I’m relying on crap^H^H^H^Hstuff like dispatch_get_specific to provide that kind of context without introducing something like Quick’s global “World”.

Russ

···

On Feb 25, 2016, at 2:47 PM, Stephen Celis via swift-evolution <swift-evolution@swift.org> wrote:

I'm reopening a topic that has already been discussed here at length[1]: setup closures and `self`-binding closures.

I've been wondering if Swift could adopt what Kotlin calls "extension function expressions"[2]. These would allow us to encode a closure's receiver type (`self`) into the closure type itself, providing a powerful, type-safe way to define DSLs.

Erica's earlier draft proposed this builder pattern:

   with let task = NSTask() {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

With extension functions, we could approach something similar:

   func with<T>(value: T, body: T.() -> ()) -> T {
       value.body()
       return value
   }

   let task = with(NSTask()) {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

Or, using the `then`[3] pattern:

   protocol Builder {}
   extension Builder {
       func then(body: Self.() -> ()) -> Self {
           body()
           return self
       }
   }
   extension NSTask: Builder {}

   let task = NSTask().then {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

How about BDD-style frameworks (like Quick/Nimble[4] and Spectre[5])?

   describe("a person") {
       let person = Person(name: "Kyle")

       it("has a name") {
           try expect(person.name) == "Kyle"
       }
   }

And HTML builders?

   html {
       head { title("Hello, World!") }
   }

And block-based, transactional APIs?

   db.inTransaction {
       delete("users", "first_name = ?", ["Jake"])
   }

The main benefits have been previously discussed:

1. The ability to remove noise ("$0" everywhere)
2. The ability to avoid defining globals (in favor of a safer, scoped interface)

Would such an enhancement be feasible?

---
Stephen

Footnotes:

[1] A probably-incomplete list:
- "Idea for enabling DSLs: bind to self in closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000114.html
- "Request for Discussion: Setup closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000211.html
- "Method cascading (was Re: Request for Discussion: Setup closures)": https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151130/000729.html
- "Fluent syntax (replacing void with a useful default return value)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/374
- "Lexical scope statement (with .. do)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1408
- "Scoped resources (like C# using statement)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1641
- "Customized Inline Init Closure": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1946
- "Then Support": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2054
- "Draft proposal: multi-property assignment .= operator": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2960
- "Custom default names for arguments of closures": http://thread.gmane.org/gmane.comp.lang.swift.evolution/6969
- https://bugs.swift.org/browse/SR-160

[2] https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver
[3] https://github.com/devxoul/Then
[4] https://github.com/Quick/Quick
[5] https://github.com/kylef/Spectre

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Radek Pietruszewski) #4

I have chills when I hear the idea of a closure changing the `self` from underneath me. JavaScript made me this way.

Of course, this is different than JavaScript, because it’s type-safe and you have to explicitly make a specific closure behave this way.

Still:
- I fear that this can be awfully confusing because there’s no indication on call site that the closure has a different `self`.
- what if you do want to use your “outer self” inside the self-binding closure? Sure, in some cases, you could differentiate by `foo` and `self.foo`, but I suspect most self-binding closures would also be @noescape. And so, back to the JavaScript-like convention of `let this = self`? Ugh :frowning:

I do like that this syntax is not super noisy with all the $0’s, and also has the advantage that it doesn’t break when you only have a single expression (https://github.com/devxoul/Then#trouble-shooting). But maybe it’s not the way to go.

— Radek

···

On 25 Feb 2016, at 23:47, Stephen Celis via swift-evolution <swift-evolution@swift.org> wrote:

I'm reopening a topic that has already been discussed here at length[1]: setup closures and `self`-binding closures.

I've been wondering if Swift could adopt what Kotlin calls "extension function expressions"[2]. These would allow us to encode a closure's receiver type (`self`) into the closure type itself, providing a powerful, type-safe way to define DSLs.

Erica's earlier draft proposed this builder pattern:

   with let task = NSTask() {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

With extension functions, we could approach something similar:

   func with<T>(value: T, body: T.() -> ()) -> T {
       value.body()
       return value
   }

   let task = with(NSTask()) {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

Or, using the `then`[3] pattern:

   protocol Builder {}
   extension Builder {
       func then(body: Self.() -> ()) -> Self {
           body()
           return self
       }
   }
   extension NSTask: Builder {}

   let task = NSTask().then {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

How about BDD-style frameworks (like Quick/Nimble[4] and Spectre[5])?

   describe("a person") {
       let person = Person(name: "Kyle")

       it("has a name") {
           try expect(person.name) == "Kyle"
       }
   }

And HTML builders?

   html {
       head { title("Hello, World!") }
   }

And block-based, transactional APIs?

   db.inTransaction {
       delete("users", "first_name = ?", ["Jake"])
   }

The main benefits have been previously discussed:

1. The ability to remove noise ("$0" everywhere)
2. The ability to avoid defining globals (in favor of a safer, scoped interface)

Would such an enhancement be feasible?

---
Stephen

Footnotes:

[1] A probably-incomplete list:
- "Idea for enabling DSLs: bind to self in closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000114.html
- "Request for Discussion: Setup closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000211.html
- "Method cascading (was Re: Request for Discussion: Setup closures)": https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151130/000729.html
- "Fluent syntax (replacing void with a useful default return value)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/374
- "Lexical scope statement (with .. do)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1408
- "Scoped resources (like C# using statement)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1641
- "Customized Inline Init Closure": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1946
- "Then Support": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2054
- "Draft proposal: multi-property assignment .= operator": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2960
- "Custom default names for arguments of closures": http://thread.gmane.org/gmane.comp.lang.swift.evolution/6969
- https://bugs.swift.org/browse/SR-160

[2] https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver
[3] https://github.com/devxoul/Then
[4] https://github.com/Quick/Quick
[5] https://github.com/kylef/Spectre

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Eugene Gubin) #5

+1 very interesting idea

···

2016-02-26 9:09 GMT+03:00 Russ Bishop via swift-evolution < swift-evolution@swift.org>:

+1 to this or something like it.

Right now I’m relying on crap^H^H^H^Hstuff like dispatch_get_specific to
provide that kind of context without introducing something like Quick’s
global “World”.

Russ

> On Feb 25, 2016, at 2:47 PM, Stephen Celis via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I'm reopening a topic that has already been discussed here at length[1]:
setup closures and `self`-binding closures.
>
> I've been wondering if Swift could adopt what Kotlin calls "extension
function expressions"[2]. These would allow us to encode a closure's
receiver type (`self`) into the closure type itself, providing a powerful,
type-safe way to define DSLs.
>
> Erica's earlier draft proposed this builder pattern:
>
> with let task = NSTask() {
> launchPath = "/usr/bin/mdfind"
> arguments = ["kMDItemDisplayName == *.playground"]
> standardOutput = pipe
> }
>
> With extension functions, we could approach something similar:
>
> func with<T>(value: T, body: T.() -> ()) -> T {
> value.body()
> return value
> }
>
> let task = with(NSTask()) {
> launchPath = "/usr/bin/mdfind"
> arguments = ["kMDItemDisplayName == *.playground"]
> standardOutput = pipe
> }
>
> Or, using the `then`[3] pattern:
>
> protocol Builder {}
> extension Builder {
> func then(body: Self.() -> ()) -> Self {
> body()
> return self
> }
> }
> extension NSTask: Builder {}
>
> let task = NSTask().then {
> launchPath = "/usr/bin/mdfind"
> arguments = ["kMDItemDisplayName == *.playground"]
> standardOutput = pipe
> }
>
> How about BDD-style frameworks (like Quick/Nimble[4] and Spectre[5])?
>
> describe("a person") {
> let person = Person(name: "Kyle")
>
> it("has a name") {
> try expect(person.name) == "Kyle"
> }
> }
>
> And HTML builders?
>
> html {
> head { title("Hello, World!") }
> }
>
> And block-based, transactional APIs?
>
> db.inTransaction {
> delete("users", "first_name = ?", ["Jake"])
> }
>
> The main benefits have been previously discussed:
>
> 1. The ability to remove noise ("$0" everywhere)
> 2. The ability to avoid defining globals (in favor of a safer, scoped
interface)
>
> Would such an enhancement be feasible?
>
> ---
> Stephen
>
> Footnotes:
>
> [1] A probably-incomplete list:
> - "Idea for enabling DSLs: bind to self in closures":
https://lists.swift.org/pipermail/swift-evolution/2015-December/000114.html
> - "Request for Discussion: Setup closures":
https://lists.swift.org/pipermail/swift-evolution/2015-December/000211.html
> - "Method cascading (was Re: Request for Discussion: Setup closures)":
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151130/000729.html
> - "Fluent syntax (replacing void with a useful default return value)":
http://thread.gmane.org/gmane.comp.lang.swift.evolution/374
> - "Lexical scope statement (with .. do)":
http://thread.gmane.org/gmane.comp.lang.swift.evolution/1408
> - "Scoped resources (like C# using statement)":
http://thread.gmane.org/gmane.comp.lang.swift.evolution/1641
> - "Customized Inline Init Closure":
http://thread.gmane.org/gmane.comp.lang.swift.evolution/1946
> - "Then Support":
http://thread.gmane.org/gmane.comp.lang.swift.evolution/2054
> - "Draft proposal: multi-property assignment .= operator":
http://thread.gmane.org/gmane.comp.lang.swift.evolution/2960
> - "Custom default names for arguments of closures":
http://thread.gmane.org/gmane.comp.lang.swift.evolution/6969
> - https://bugs.swift.org/browse/SR-160
>
> [2]
https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver
> [3] https://github.com/devxoul/Then
> [4] https://github.com/Quick/Quick
> [5] https://github.com/kylef/Spectre
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#6

I have chills when I hear the idea of a closure changing the `self` from underneath me. JavaScript made me this way.

Of course, this is different than JavaScript, because it’s type-safe and you have to explicitly make a specific closure behave this way.

Still:
- I fear that this can be awfully confusing because there’s no indication on call site that the closure has a different `self`.

Is this much different than the argument made against implicit vs. explicit `self` when calling methods and properties? Couldn't the context and editor make this fairly easy to disambiguate on the event that it _is_ confusing?

I agree that `with` presented problems in JavaScript (not just ambiguity, but forward-compatibility), and though `with` could be built rather easily in Swift using extension functions, it's not the core concept here (in any case, a protocol extension-based `then` would probably be preferred over `with`).

Ruby is another type-unsafe language with a community that heavily employs these kinds of DSLs via `instance_{eval,exec}`. The few issues I have with Ruby's system disappear with type safety and compile-time guarantees.

- what if you do want to use your “outer self” inside the self-binding closure? Sure, in some cases, you could differentiate by `foo` and `self.foo`, but I suspect most self-binding closures would also be @noescape. And so, back to the JavaScript-like convention of `let this = self`? Ugh :frowning:

In the past life I spent with Ruby, I don't ever remember fighting this, but in those rare cases that you want to refer to "outer" self, I don't see a prelude of `let value = self` or `let valueNeededForClosure = property` being a problem. Capture lists offer a shorthand:

    db.inTransaction { [name] in
        delete("users", "name = ?", [name])
    }

(While I believe it would be possible for the compiler to cascade to outer `self` methods and properties, I'm not convinced this is a good idea.)

I do like that this syntax is not super noisy with all the $0’s, and also has the advantage that it doesn’t break when you only have a single expression (https://github.com/devxoul/Then#trouble-shooting). But maybe it’s not the way to go.

Was there an earlier version you preferred (see my long list at the beginning of this thread)? Do you have alternate ideas or ways to improve upon the idea of using extension functions?

Stephen

···

On Feb 29, 2016, at 7:33 AM, Radosław Pietruszewski <radexpl@gmail.com> wrote:


(Brent Royal-Gordon) #7

- I fear that this can be awfully confusing because there’s no indication on call site that the closure has a different `self`.
- what if you do want to use your “outer self” inside the self-binding closure? Sure, in some cases, you could differentiate by `foo` and `self.foo`, but I suspect most self-binding closures would also be @noescape. And so, back to the JavaScript-like convention of `let this = self`? Ugh :frowning:

Personally, I wouldn't mind having the feature structured in the following fashion:

* You can use `self` as the internal name of any parameter to any function. (Though perhaps not in a method, which already has an implicit parameter with the internal name `self`.)
* If you do, that parameter is the receiver of all receiverless method calls.
* A closure with `self: T` in its parameter list is simply a hint to SourceKit that its code completion should name the parameter `self`.

That way, any closure which rebound self would be explicitly marked at the top with `self in`, and if you wanted to access the outer `self`, you could always simply give the parameter a different name.

This would add a small syntactic burden to uses of `with` and other DSLs, but it might be worth it to make the behavior explicit.

···

--
Brent Royal-Gordon
Architechies


(Pierre Monod-Broca) #8

+1 on changing the meaning of `self`, it's scary

···

Le 29 févr. 2016 à 13:33, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> a écrit :

I have chills when I hear the idea of a closure changing the `self` from underneath me. JavaScript made me this way.

Of course, this is different than JavaScript, because it’s type-safe and you have to explicitly make a specific closure behave this way.

Still:
- I fear that this can be awfully confusing because there’s no indication on call site that the closure has a different `self`.
- what if you do want to use your “outer self” inside the self-binding closure? Sure, in some cases, you could differentiate by `foo` and `self.foo`, but I suspect most self-binding closures would also be @noescape. And so, back to the JavaScript-like convention of `let this = self`? Ugh :frowning:

I do like that this syntax is not super noisy with all the $0’s, and also has the advantage that it doesn’t break when you only have a single expression (https://github.com/devxoul/Then#trouble-shooting). But maybe it’s not the way to go.

— Radek

On 25 Feb 2016, at 23:47, Stephen Celis via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I'm reopening a topic that has already been discussed here at length[1]: setup closures and `self`-binding closures.

I've been wondering if Swift could adopt what Kotlin calls "extension function expressions"[2]. These would allow us to encode a closure's receiver type (`self`) into the closure type itself, providing a powerful, type-safe way to define DSLs.

Erica's earlier draft proposed this builder pattern:

   with let task = NSTask() {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

With extension functions, we could approach something similar:

   func with<T>(value: T, body: T.() -> ()) -> T {
       value.body()
       return value
   }

   let task = with(NSTask()) {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

Or, using the `then`[3] pattern:

   protocol Builder {}
   extension Builder {
       func then(body: Self.() -> ()) -> Self {
           body()
           return self
       }
   }
   extension NSTask: Builder {}

   let task = NSTask().then {
       launchPath = "/usr/bin/mdfind"
       arguments = ["kMDItemDisplayName == *.playground"]
       standardOutput = pipe
   }

How about BDD-style frameworks (like Quick/Nimble[4] and Spectre[5])?

   describe("a person") {
       let person = Person(name: "Kyle")

       it("has a name") {
           try expect(person.name) == "Kyle"
       }
   }

And HTML builders?

   html {
       head { title("Hello, World!") }
   }

And block-based, transactional APIs?

   db.inTransaction {
       delete("users", "first_name = ?", ["Jake"])
   }

The main benefits have been previously discussed:

1. The ability to remove noise ("$0" everywhere)
2. The ability to avoid defining globals (in favor of a safer, scoped interface)

Would such an enhancement be feasible?

---
Stephen

Footnotes:

[1] A probably-incomplete list:
- "Idea for enabling DSLs: bind to self in closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000114.html
- "Request for Discussion: Setup closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000211.html
- "Method cascading (was Re: Request for Discussion: Setup closures)": https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151130/000729.html
- "Fluent syntax (replacing void with a useful default return value)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/374
- "Lexical scope statement (with .. do)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1408
- "Scoped resources (like C# using statement)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1641
- "Customized Inline Init Closure": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1946
- "Then Support": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2054
- "Draft proposal: multi-property assignment .= operator": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2960
- "Custom default names for arguments of closures": http://thread.gmane.org/gmane.comp.lang.swift.evolution/6969
- https://bugs.swift.org/browse/SR-160

[2] https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver
[3] https://github.com/devxoul/Then
[4] https://github.com/Quick/Quick
[5] https://github.com/kylef/Spectre

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Pierre Monod-Broca) #9

+1 on the idea.

I'm less convinced by the suggested syntax, to me it feels a bit weird.

I'm thinking an attribute on the closure's first parameter, for exemple (feel free to suggest other names):

func with<T>(value: T, body: (bound T) -> ()) -> T {
    body(value)
    return value
}

···

Le 26 févr. 2016 à 08:22, Eugene Gubin via swift-evolution <swift-evolution@swift.org> a écrit :

+1 very interesting idea

2016-02-26 9:09 GMT+03:00 Russ Bishop via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
+1 to this or something like it.

Right now I’m relying on crap^H^H^H^Hstuff like dispatch_get_specific to provide that kind of context without introducing something like Quick’s global “World”.

Russ

> On Feb 25, 2016, at 2:47 PM, Stephen Celis via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> I'm reopening a topic that has already been discussed here at length[1]: setup closures and `self`-binding closures.
>
> I've been wondering if Swift could adopt what Kotlin calls "extension function expressions"[2]. These would allow us to encode a closure's receiver type (`self`) into the closure type itself, providing a powerful, type-safe way to define DSLs.
>
> Erica's earlier draft proposed this builder pattern:
>
> with let task = NSTask() {
> launchPath = "/usr/bin/mdfind"
> arguments = ["kMDItemDisplayName == *.playground"]
> standardOutput = pipe
> }
>
> With extension functions, we could approach something similar:
>
> func with<T>(value: T, body: T.() -> ()) -> T {
> value.body()
> return value
> }
>
> let task = with(NSTask()) {
> launchPath = "/usr/bin/mdfind"
> arguments = ["kMDItemDisplayName == *.playground"]
> standardOutput = pipe
> }
>
> Or, using the `then`[3] pattern:
>
> protocol Builder {}
> extension Builder {
> func then(body: Self.() -> ()) -> Self {
> body()
> return self
> }
> }
> extension NSTask: Builder {}
>
> let task = NSTask().then {
> launchPath = "/usr/bin/mdfind"
> arguments = ["kMDItemDisplayName == *.playground"]
> standardOutput = pipe
> }
>
> How about BDD-style frameworks (like Quick/Nimble[4] and Spectre[5])?
>
> describe("a person") {
> let person = Person(name: "Kyle")
>
> it("has a name") {
> try expect(person.name <http://person.name/>) == "Kyle"
> }
> }
>
> And HTML builders?
>
> html {
> head { title("Hello, World!") }
> }
>
> And block-based, transactional APIs?
>
> db.inTransaction {
> delete("users", "first_name = ?", ["Jake"])
> }
>
> The main benefits have been previously discussed:
>
> 1. The ability to remove noise ("$0" everywhere)
> 2. The ability to avoid defining globals (in favor of a safer, scoped interface)
>
> Would such an enhancement be feasible?
>
> ---
> Stephen
>
> Footnotes:
>
> [1] A probably-incomplete list:
> - "Idea for enabling DSLs: bind to self in closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000114.html
> - "Request for Discussion: Setup closures": https://lists.swift.org/pipermail/swift-evolution/2015-December/000211.html
> - "Method cascading (was Re: Request for Discussion: Setup closures)": https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151130/000729.html
> - "Fluent syntax (replacing void with a useful default return value)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/374
> - "Lexical scope statement (with .. do)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1408
> - "Scoped resources (like C# using statement)": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1641
> - "Customized Inline Init Closure": http://thread.gmane.org/gmane.comp.lang.swift.evolution/1946
> - "Then Support": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2054
> - "Draft proposal: multi-property assignment .= operator": http://thread.gmane.org/gmane.comp.lang.swift.evolution/2960
> - "Custom default names for arguments of closures": http://thread.gmane.org/gmane.comp.lang.swift.evolution/6969
> - https://bugs.swift.org/browse/SR-160
>
> [2] https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver
> [3] https://github.com/devxoul/Then
> [4] https://github.com/Quick/Quick
> [5] https://github.com/kylef/Spectre
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#10

The `self in` solution was actually one of the first suggestions on this list:

https://lists.swift.org/pipermail/swift-evolution/2015-December/000114.html

I do think it gets rather wordy in DSLs, though, and that implicit `self` should be favored if it works (for the same reason we allow implicit `self`). There's a lot of noise:

    html { self in
        head { self in
            title("Hello")
        }
        body { self in
            section { self in
                p("Hello, ", span(name))
            }
        }
    }

Vs.

    html {
        head {
            title("Hello")
        }
        body {
            section {
                p("Hello, ", span(name))
            }
        }
    }

Even "$0" feels less noisy, depending on the DSL:

    html {
        $0.head {
            $0.title("Hello")
        }
        $0.body {
            $0.section {
                $0.p("Hello, ", $0.span(name))
            }
        }
    }

···

On Feb 29, 2016, at 6:38 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

Personally, I wouldn't mind having the feature structured in the following fashion:

* You can use `self` as the internal name of any parameter to any function. (Though perhaps not in a method, which already has an implicit parameter with the internal name `self`.)
* If you do, that parameter is the receiver of all receiverless method calls.
* A closure with `self: T` in its parameter list is simply a hint to SourceKit that its code completion should name the parameter `self`.

That way, any closure which rebound self would be explicitly marked at the top with `self in`, and if you wanted to access the outer `self`, you could always simply give the parameter a different name.

This would add a small syntactic burden to uses of `with` and other DSLs, but it might be worth it to make the behavior explicit.

--
Stephen


#11

While I'm not married to `T.() -> ()`, I do like that it:

- Separates the self parameter from the parameter list
- Avoids an additional keyword

We could also try reusing the recently removed curry syntax:

    func with<T>(value: T, body: (T)() -> Void) -> T {
        value.body(value)
        return value
    }

Given that curried versions of instance methods are available on the class, and given the fact that the instance versions of these methods have a bound `self` (and would likely have an extension function signature), it might make more sense than using dot-notation.

Stephen

···

On Feb 26, 2016, at 7:21 AM, Pierre Monod-Broca via swift-evolution <swift-evolution@swift.org> wrote:

I'm less convinced by the suggested syntax, to me it feels a bit weird.

I'm thinking an attribute on the closure's first parameter, for exemple (feel free to suggest other names):

func with<T>(value: T, body: (bound T) -> ()) -> T {
    body(value)
    return value
}


(Brent Royal-Gordon) #12

I'm thinking an attribute on the closure's first parameter, for exemple (feel free to suggest other names):

func with<T>(value: T, body: (bound T) -> ()) -> T {

Is there a reason to avoid the obvious answer?

  func with<T>(value: T, body: (self: T) -> ()) -> T {

···

--
Brent Royal-Gordon
Architechies


#13

I don't see any reason why that couldn't work.

With that change would the call site may change, too?

    body(self)

Stephen

···

On Feb 29, 2016, at 3:59 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

I'm thinking an attribute on the closure's first parameter, for exemple (feel free to suggest other names):

func with<T>(value: T, body: (bound T) -> ()) -> T {

Is there a reason to avoid the obvious answer?

  func with<T>(value: T, body: (self: T) -> ()) -> T {