Pitch: Compound name `foo(:)` for nullary functions


(Jacob Bandes-Storch) #1

Evolutioniers,

*Compound name syntax* — foo(_:), foo(bar:), foo(bar:baz:) — is used to
disambiguate references to functions. (You might've used it inside a
#selector expression.) But there's currently no compound name for a
function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name syntax.
And the simple reference "let myfn = foo" is ambiguous because it could
refer to any of the four. A workaround is to specify a contextual type,
e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while
ago, and there was some discussion in JIRA about it. I'd like to continue
exploring solutions here and then write up a formal proposal.

To kick off the discussion, *I'd like to propose foo(:slight_smile: for nullary
functions.*

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument
labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.
- the parallel between #selector(foo(:)) and @selector(foo) is not quite as
obvious as between #selector(foo(_:)) and @selector(foo:).

For the sake of discussion, another option would be *foo(_)*. This was my
original choice, and I like that the number of colons matches the number of
parameters. However, it's a little less obvious as a function reference. It
would preclude _ from acting as an actual identifier, and might conflict
with pattern-matching syntax (although it appears functions can't be
compared with ~= anyway).

Looking forward to everyone's bikeshed color ideas,
Jacob


(Slava Pestov) #2

Evolutioniers,

Compound name syntax — foo(_:), foo(bar:), foo(bar:baz:) — is used to disambiguate references to functions. (You might've used it inside a #selector expression.) But there's currently no compound name for a function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name syntax. And the simple reference "let myfn = foo" is ambiguous because it could refer to any of the four. A workaround is to specify a contextual type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while ago, and there was some discussion in JIRA about it. I'd like to continue exploring solutions here and then write up a formal proposal.

To kick off the discussion, I'd like to propose foo(:slight_smile: for nullary functions.

I like this idea.

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.
- the parallel between #selector(foo(:)) and @selector(foo) is not quite as obvious as between #selector(foo(_:)) and @selector(foo:).

For the sake of discussion, another option would be foo(_). This was my original choice, and I like that the number of colons matches the number of parameters. However, it's a little less obvious as a function reference. It would preclude _ from acting as an actual identifier, and might conflict with pattern-matching syntax (although it appears functions can't be compared with ~= anyway).

foo(_) looks like a pattern to me. Even if it doesn’t introduce ambiguity in the grammar it might be confusing.

···

On Feb 21, 2017, at 11:05 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Looking forward to everyone's bikeshed color ideas,
Jacob
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Hart) #3

Evolutioniers,

Compound name syntax — foo(_:), foo(bar:), foo(bar:baz:) — is used to disambiguate references to functions. (You might've used it inside a #selector expression.) But there's currently no compound name for a function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name syntax. And the simple reference "let myfn = foo" is ambiguous because it could refer to any of the four. A workaround is to specify a contextual type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 for this a while ago, and there was some discussion in JIRA about it. I'd like to continue exploring solutions here and then write up a formal proposal.

To kick off the discussion, I'd like to propose foo(:slight_smile: for nullary functions.

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.

This is a big disadvantage for me and will potentially be very surprising for newcomers.

- the parallel between #selector(foo(:))and @selector(foo) is not quite as obvious as between #selector(foo(_:))and @selector(foo:).

For the sake of discussion, another option would be foo(_). This was my original choice, and I like that the number of colons matches the number of parameters. However, it's a little less obvious as a function reference. It would preclude _ from acting as an actual identifier, and might conflict with pattern-matching syntax (although it appears functions can't be compared with ~= anyway).

This is my favorite syntax so far.

···

On 22 Feb 2017, at 08:05, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Looking forward to everyone's bikeshed color ideas,
Jacob
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #4

I like this idea. I think you made the right choice of syntax given the alternatives considered. To me `foo(_)` and `foo(:)` equally imply presence of an argument. The former looks like an anonymous (unnamed) argument and the latter includes the colon which only follows an argument. Between the two `foo(:)` is the better choice because it doesn’t look like a pattern as has been pointed out.

I’m going to do a little brainstorming to try and come up with something that works and doesn’t imply an argument at all but suspect I’ll come up empty handed.

···

On Feb 22, 2017, at 1:05 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Evolutioniers,

Compound name syntax — foo(_:), foo(bar:), foo(bar:baz:) — is used to disambiguate references to functions. (You might've used it inside a #selector expression.) But there's currently no compound name for a function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name syntax. And the simple reference "let myfn = foo" is ambiguous because it could refer to any of the four. A workaround is to specify a contextual type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while ago, and there was some discussion in JIRA about it. I'd like to continue exploring solutions here and then write up a formal proposal.

To kick off the discussion, I'd like to propose foo(:slight_smile: for nullary functions.

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.
- the parallel between #selector(foo(:)) and @selector(foo) is not quite as obvious as between #selector(foo(_:)) and @selector(foo:).

For the sake of discussion, another option would be foo(_). This was my original choice, and I like that the number of colons matches the number of parameters. However, it's a little less obvious as a function reference. It would preclude _ from acting as an actual identifier, and might conflict with pattern-matching syntax (although it appears functions can't be compared with ~= anyway).

Looking forward to everyone's bikeshed color ideas,
Jacob
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#5

+1

I prefer foo(:slight_smile: because it matches with empty dictional literal [:].

Also, foo(_) potentially introduce a confusion.
Remember that this syntax can be appear in a pattern.

struct S {
    let val: Int
}
func newS() -> S { return S(val: 0) }
func newS(_ val: Int) -> S { return S(val: val) }

func ~= (pat: () -> S, obj: S) -> Bool { return pat().val == obj.val }

let obj = S(val: 0)
switch obj {
case newS(_): // Is this a pattern???
    break
default:
    break
}
···

2017-02-22 16:05 GMT+09:00 Jacob Bandes-Storch via swift-evolution < swift-evolution@swift.org>:

Evolutioniers,

*Compound name syntax* — foo(_:), foo(bar:), foo(bar:baz:) — is used to
disambiguate references to functions. (You might've used it inside a
#selector expression.) But there's currently no compound name for a
function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name
syntax. And the simple reference "let myfn = foo" is ambiguous because it
could refer to any of the four. A workaround is to specify a contextual
type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while
ago, and there was some discussion in JIRA about it. I'd like to continue
exploring solutions here and then write up a formal proposal.

To kick off the discussion, *I'd like to propose foo(:slight_smile: for nullary
functions.*

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument
labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.
- the parallel between #selector(foo(:)) and @selector(foo) is not quite
as obvious as between #selector(foo(_:)) and @selector(foo:).

For the sake of discussion, another option would be *foo(_)*. This was my
original choice, and I like that the number of colons matches the number of
parameters. However, it's a little less obvious as a function reference. It
would preclude _ from acting as an actual identifier, and might conflict
with pattern-matching syntax (although it appears functions can't be
compared with ~= anyway).

Looking forward to everyone's bikeshed color ideas,
Jacob

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


(Ben Rimmington) #6

Would the following be an option?

   foo() // Function call expression.
  `foo()` // Function reference (using backticks).

-- Ben

···

On 22 Feb 2017, at 07:05, Jacob Bandes-Storch wrote:

Compound name syntax — foo(_:), foo(bar:), foo(bar:baz:) — is used to disambiguate references to functions. (You might've used it inside a #selector expression.) But there's currently no compound name for a function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name syntax. And the simple reference "let myfn = foo" is ambiguous because it could refer to any of the four. A workaround is to specify a contextual type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while ago, and there was some discussion in JIRA about it. I'd like to continue exploring solutions here and then write up a formal proposal.


(Tino) #7

I never liked the compound name syntax because parenthesis are deeply connected to the application of function, and it breaks with the way selectors are specified in Objective-C.

If this topic is touched once again, imho it should be done thoroughly — with a syntax that can really eliminate all ambiguity.

Instead of
foo(bar:baz) as (String, Double) -> Void

I'd prefer something along the line of

foo:Void,bar:String,baz:Double


(Anton Zhilin) #8

+1 to foo(:slight_smile: version.
I can easily see placeholder arguments as a sugary syntax for closures:

func bar(_ x: Int, _ y: Double)
let f = bar(_, 42) // the same as:
let f = { (x: Int) in bar(x, 42) }

Now, let’s view a single-parameter version:

func foo(_ x: Int)
let f = foo(_) // the same as:
let f = { (x: Int) in foo(x) }


(Jordan Rose) #9

I don't have a good answer for this, but I'll vote against 'foo(:)' because that's what a lot of people think the name of 'foo(_:)' should be. I'd rather be able to offer fix-its for that even when you have both 'foo()' and 'foo(_:)' defined. I'd rather go with 'foo(_)' despite the tiny ambiguity in pattern contexts.

(I'm personally in favor of killing unapplied function references altogether in favor of closures, on the grounds that they are overly terse, make type-checking more complicated, and often lead to retain cycles. Then we'd only need this for #selector, and it's perfectly unambiguous to use 'foo()' there. But I wasn't planning to fight that particular battle now, and it is rather annoying to require the 'as' in the meantime.)

Jordan

···

On Feb 21, 2017, at 23:05, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

Evolutioniers,

Compound name syntax — foo(_:), foo(bar:), foo(bar:baz:) — is used to disambiguate references to functions. (You might've used it inside a #selector expression.) But there's currently no compound name for a function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name syntax. And the simple reference "let myfn = foo" is ambiguous because it could refer to any of the four. A workaround is to specify a contextual type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while ago, and there was some discussion in JIRA about it. I'd like to continue exploring solutions here and then write up a formal proposal.

To kick off the discussion, I'd like to propose foo(:slight_smile: for nullary functions.

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.
- the parallel between #selector(foo(:)) and @selector(foo) is not quite as obvious as between #selector(foo(_:)) and @selector(foo:).

For the sake of discussion, another option would be foo(_). This was my original choice, and I like that the number of colons matches the number of parameters. However, it's a little less obvious as a function reference. It would preclude _ from acting as an actual identifier, and might conflict with pattern-matching syntax (although it appears functions can't be compared with ~= anyway).

Looking forward to everyone's bikeshed color ideas,
Jacob


(David Sweeris) #10

What about “foo(Void)”? It might be fairly easily confused with “foo(:Void)”, but in practice, how likely is it for someone to declare both `foo()` and `foo(_: Void)`?

- Dave Sweeris

···

On Feb 22, 2017, at 7:48 AM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

I like this idea. I think you made the right choice of syntax given the alternatives considered. To me `foo(_)` and `foo(:)` equally imply presence of an argument. The former looks like an anonymous (unnamed) argument and the latter includes the colon which only follows an argument. Between the two `foo(:)` is the better choice because it doesn’t look like a pattern as has been pointed out.

I’m going to do a little brainstorming to try and come up with something that works and doesn’t imply an argument at all but suspect I’ll come up empty handed.


(Patrick Pijnappel) #11

I'm personally in favor of foo(_), as the number of colons currently lines
up directly with the number of arguments, and it'd be good to keep it that
way.

In general though I'm very in favor of requiring the parentheses, as the
ambiguity between unparenthesized references to functions and properties
can be quite confusing/annoying.

···

On Wed, Feb 22, 2017 at 6:35 PM, David Hart via swift-evolution < swift-evolution@swift.org> wrote:

On 22 Feb 2017, at 08:05, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

Evolutioniers,

*Compound name syntax* — foo(_:), foo(bar:), foo(bar:baz:) — is used to
disambiguate references to functions. (You might've used it inside a
#selector expression.) But there's currently no compound name for a
function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name
syntax. And the simple reference "let myfn = foo" is ambiguous because it
could refer to any of the four. A workaround is to specify a contextual
type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while
ago, and there was some discussion in JIRA about it. I'd like to continue
exploring solutions here and then write up a formal proposal.

To kick off the discussion, *I'd like to propose foo(:slight_smile: for nullary
functions.*

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument
labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.

This is a big disadvantage for me and will potentially be very surprising
for newcomers.

- the parallel between #selector(foo(:))and @selector(foo) is not quite
as obvious as between #selector(foo(_:))and @selector(foo:).

For the sake of discussion, another option would be *foo(_)*. This was my
original choice, and I like that the number of colons matches the number of
parameters. However, it's a little less obvious as a function reference. It
would preclude _ from acting as an actual identifier, and might conflict
with pattern-matching syntax (although it appears functions can't be
compared with ~= anyway).

This is my favorite syntax so far.

Looking forward to everyone's bikeshed color ideas,
Jacob

_______________________________________________
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


(Xiaodi Wu) #12

What happens when you need the backticks for the function name itself? We
can't nest them.

···

On Thu, Feb 23, 2017 at 08:16 Ben Rimmington via swift-evolution < swift-evolution@swift.org> wrote:

On 22 Feb 2017, at 07:05, Jacob Bandes-Storch wrote:

*Compound name syntax* — foo(_:), foo(bar:), foo(bar:baz:) — is used to
disambiguate references to functions. (You might've used it inside a
#selector expression.) But there's currently no compound name for a
function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name
syntax. And the simple reference "let myfn = foo" is ambiguous because it
could refer to any of the four. A workaround is to specify a contextual
type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while
ago, and there was some discussion in JIRA about it. I'd like to continue
exploring solutions here and then write up a formal proposal.

Would the following be an option?

foo() // Function call expression.
`foo()` // Function reference (using backticks).

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


(Derrick Ho) #13

The back tick option is interesting. Back tick means "don't treat this as
an expression" which allows us to use keywords in certain areas but have
them. Act as something that isn't a keyword.

let f = `foo()`

However looking at it like this it almost looks like a string.

···

On Thu, Feb 23, 2017 at 9:16 AM Ben Rimmington via swift-evolution < swift-evolution@swift.org> wrote:

On 22 Feb 2017, at 07:05, Jacob Bandes-Storch wrote:

*Compound name syntax* — foo(_:), foo(bar:), foo(bar:baz:) — is used to
disambiguate references to functions. (You might've used it inside a
#selector expression.) But there's currently no compound name for a
function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name
syntax. And the simple reference "let myfn = foo" is ambiguous because it
could refer to any of the four. A workaround is to specify a contextual
type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while
ago, and there was some discussion in JIRA about it. I'd like to continue
exploring solutions here and then write up a formal proposal.

Would the following be an option?

foo() // Function call expression.
`foo()` // Function reference (using backticks).

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


(Matthew Johnson) #14

+1 to foo(:slight_smile: version.
I can easily see placeholder arguments as a sugary syntax for closures:

This shorthand has been explicitly rejected several times in favor of the $ argument shorthand.

···

On Feb 23, 2017, at 12:52 PM, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

func bar(_ x: Int, _ y: Double)
let f = bar(_, 42) // the same as:
let f = { (x: Int) in bar(x, 42) }
Now, let’s view a single-parameter version:

func foo(_ x: Int)
let f = foo(_) // the same as:
let f = { (x: Int) in foo(x) }
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Jordan Rose) #15

Whoops, after hitting Send I realized that I don't want to kill references to non-member functions, which means it's still useful to have a syntax for this. Still, there is one simple and unambiguous spelling when you need it…

{ foo() }

trollface.gif,
Jordan

···

On Feb 24, 2017, at 15:56, Jordan Rose <jordan_rose@apple.com> wrote:

I don't have a good answer for this, but I'll vote against 'foo(:)' because that's what a lot of people think the name of 'foo(_:)' should be. I'd rather be able to offer fix-its for that even when you have both 'foo()' and 'foo(_:)' defined. I'd rather go with 'foo(_)' despite the tiny ambiguity in pattern contexts.

(I'm personally in favor of killing unapplied function references altogether in favor of closures, on the grounds that they are overly terse, make type-checking more complicated, and often lead to retain cycles. Then we'd only need this for #selector, and it's perfectly unambiguous to use 'foo()' there. But I wasn't planning to fight that particular battle now, and it is rather annoying to require the 'as' in the meantime.)

Jordan

On Feb 21, 2017, at 23:05, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:

Evolutioniers,

Compound name syntax — foo(_:), foo(bar:), foo(bar:baz:) — is used to disambiguate references to functions. (You might've used it inside a #selector expression.) But there's currently no compound name for a function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name syntax. And the simple reference "let myfn = foo" is ambiguous because it could refer to any of the four. A workaround is to specify a contextual type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while ago, and there was some discussion in JIRA about it. I'd like to continue exploring solutions here and then write up a formal proposal.

To kick off the discussion, I'd like to propose foo(:slight_smile: for nullary functions.

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.
- the parallel between #selector(foo(:)) and @selector(foo) is not quite as obvious as between #selector(foo(_:)) and @selector(foo:).

For the sake of discussion, another option would be foo(_). This was my original choice, and I like that the number of colons matches the number of parameters. However, it's a little less obvious as a function reference. It would preclude _ from acting as an actual identifier, and might conflict with pattern-matching syntax (although it appears functions can't be compared with ~= anyway).

Looking forward to everyone's bikeshed color ideas,
Jacob


(David Hart) #16

I don't have a good answer for this, but I'll vote against 'foo(:)' because that's what a lot of people think the name of 'foo(_:)' should be. I'd rather be able to offer fix-its for that even when you have both 'foo()' and 'foo(_:)' defined. I'd rather go with 'foo(_)' despite the tiny ambiguity in pattern contexts.

(I'm personally in favor of killing unapplied function references altogether in favor of closures, on the grounds that they are overly terse, make type-checking more complicated, and often lead to retain cycles. Then we'd only need this for #selector, and it's perfectly unambiguous to use 'foo()' there. But I wasn't planning to fight that particular battle now, and it is rather annoying to require the 'as' in the meantime.)

It is potentially going to be hard to fight that battle. I think a lot of functional/Haskell people love them and would be sad to see them go away (I plead guilty). But it isn’t a well known part of the language so I don’t think the general community would miss it.

···

On 25 Feb 2017, at 00:56, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Jordan

On Feb 21, 2017, at 23:05, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:

Evolutioniers,

Compound name syntax — foo(_:), foo(bar:), foo(bar:baz:) — is used to disambiguate references to functions. (You might've used it inside a #selector expression.) But there's currently no compound name for a function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name syntax. And the simple reference "let myfn = foo" is ambiguous because it could refer to any of the four. A workaround is to specify a contextual type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while ago, and there was some discussion in JIRA about it. I'd like to continue exploring solutions here and then write up a formal proposal.

To kick off the discussion, I'd like to propose foo(:slight_smile: for nullary functions.

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.
- the parallel between #selector(foo(:)) and @selector(foo) is not quite as obvious as between #selector(foo(_:)) and @selector(foo:).

For the sake of discussion, another option would be foo(_). This was my original choice, and I like that the number of colons matches the number of parameters. However, it's a little less obvious as a function reference. It would preclude _ from acting as an actual identifier, and might conflict with pattern-matching syntax (although it appears functions can't be compared with ~= anyway).

Looking forward to everyone's bikeshed color ideas,
Jacob

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


(Matthew Johnson) #17

I like this idea. I think you made the right choice of syntax given the alternatives considered. To me `foo(_)` and `foo(:)` equally imply presence of an argument. The former looks like an anonymous (unnamed) argument and the latter includes the colon which only follows an argument. Between the two `foo(:)` is the better choice because it doesn’t look like a pattern as has been pointed out.

I’m going to do a little brainstorming to try and come up with something that works and doesn’t imply an argument at all but suspect I’ll come up empty handed.

What about “foo(Void)”? It might be fairly easily confused with “foo(:Void)”, but in practice, how likely is it for someone to declare both `foo()` and `foo(_: Void)`?

I almost threw out `foo(Void)` and `foo(Never)` as ideas. There is at least one problem with these. We will hopefully eventually get rid of the need to say `.self` in expressions like `Int.self`. If we are able to do that then `foo(Void)` and `foo(Never)` are syntactically valid function calls.

···

On Feb 22, 2017, at 12:30 PM, David Sweeris <davesweeris@mac.com> wrote:

On Feb 22, 2017, at 7:48 AM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

- Dave Sweeris


(Derrick Ho) #18

foo(_) seems better. A colon would imply there is an argument of which
there is none.

···

On Wed, Feb 22, 2017 at 4:52 AM Patrick Pijnappel via swift-evolution < swift-evolution@swift.org> wrote:

I'm personally in favor of foo(_), as the number of colons currently
lines up directly with the number of arguments, and it'd be good to keep it
that way.

In general though I'm very in favor of requiring the parentheses, as the
ambiguity between unparenthesized references to functions and properties
can be quite confusing/annoying.

On Wed, Feb 22, 2017 at 6:35 PM, David Hart via swift-evolution < > swift-evolution@swift.org> wrote:

On 22 Feb 2017, at 08:05, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

Evolutioniers,

*Compound name syntax* — foo(_:), foo(bar:), foo(bar:baz:) — is used to
disambiguate references to functions. (You might've used it inside a
#selector expression.) But there's currently no compound name for a
function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name
syntax. And the simple reference "let myfn = foo" is ambiguous because it
could refer to any of the four. A workaround is to specify a contextual
type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while
ago, and there was some discussion in JIRA about it. I'd like to continue
exploring solutions here and then write up a formal proposal.

To kick off the discussion, *I'd like to propose foo(:slight_smile: for nullary
functions.*

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument
labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.

This is a big disadvantage for me and will potentially be very surprising
for newcomers.

- the parallel between #selector(foo(:))and @selector(foo) is not quite as
obvious as between #selector(foo(_:))and @selector(foo:).

For the sake of discussion, another option would be *foo(_)*. This was my
original choice, and I like that the number of colons matches the number of
parameters. However, it's a little less obvious as a function reference. It
would preclude _ from acting as an actual identifier, and might conflict
with pattern-matching syntax (although it appears functions can't be
compared with ~= anyway).

This is my favorite syntax so far.

Looking forward to everyone's bikeshed color ideas,
Jacob

_______________________________________________
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

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


(Ben Rimmington) #19

func `class`() {}

`class`() // Function call.

`class()` // Function reference.

-- Ben

···

On 23 Feb 2017, at 14:23, Xiaodi Wu wrote:

What happens when you need the backticks for the function name itself? We can't nest them.


(Jacob Bandes-Storch) #20

Now that escaping with \ has been proposed for KeyPaths, this makes me
wonder whether it would be appropriate to use "\foo()" rather than
"foo(_)"/"foo(:)" ? It still feels a bit strange, as \foo() looks like
escaping the *result* of a call.

···

On Sat, Feb 25, 2017 at 1:43 PM, David Hart <david@hartbit.com> wrote:

On 25 Feb 2017, at 00:56, Jordan Rose via swift-evolution < > swift-evolution@swift.org> wrote:

I don't have a *good* answer for this, but I'll vote *against* 'foo(:)'
because that's what a lot of people think the name of 'foo(_:)' should be.
I'd rather be able to offer fix-its for that even when you have both
'foo()' and 'foo(_:)' defined. I'd rather go with 'foo(_)' despite the tiny
ambiguity in pattern contexts.

(I'm personally in favor of killing unapplied function references
altogether in favor of closures, on the grounds that they are overly terse,
make type-checking more complicated, and often lead to retain cycles. Then
we'd only need this for #selector, and it's perfectly unambiguous to use
'foo()' there. But I wasn't planning to fight that particular battle now,
and it is rather annoying to require the 'as' in the meantime.)

It is potentially going to be hard to fight that battle. I think a lot of
functional/Haskell people love them and would be sad to see them go away (I
plead guilty). But it isn’t a well known part of the language so I don’t
think the general community would miss it.

Jordan

On Feb 21, 2017, at 23:05, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

Evolutioniers,

*Compound name syntax* — foo(_:), foo(bar:), foo(bar:baz:) — is used to
disambiguate references to functions. (You might've used it inside a
#selector expression.) But there's currently no compound name for a
function with no arguments.

    func foo() {} // no compound syntax for this one :frowning:
    func foo(_ bar: Int) {} // foo(_:slight_smile:
    func foo(bar: Int) {} // foo(bar:)
    func foo(bar: String, baz: Double) {} // foo(bar:baz:)

Given these four functions, only the first one has no compound name
syntax. And the simple reference "let myfn = foo" is ambiguous because it
could refer to any of the four. A workaround is to specify a contextual
type, e.g. "let myfn = foo as () -> Void".

I filed SR-3550 <https://bugs.swift.org/browse/SR-3550> for this a while
ago, and there was some discussion in JIRA about it. I'd like to continue
exploring solutions here and then write up a formal proposal.

To kick off the discussion, *I'd like to propose foo(:slight_smile: for nullary
functions.*

Advantages:
- the colon marks a clear similarity to the foo(bar:) form when argument
labels are present.
- cutely parallels the empty dictionary literal, [:].

Disadvantages:
- violates intuition about one-colon-per-argument.
- the parallel between #selector(foo(:)) and @selector(foo) is not quite
as obvious as between #selector(foo(_:)) and @selector(foo:).

For the sake of discussion, another option would be *foo(_)*. This was my
original choice, and I like that the number of colons matches the number of
parameters. However, it's a little less obvious as a function reference. It
would preclude _ from acting as an actual identifier, and might conflict
with pattern-matching syntax (although it appears functions can't be
compared with ~= anyway).

Looking forward to everyone's bikeshed color ideas,
Jacob

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