Why doesn't Swift allow a variable and a function with the same name?


(Michael Gubik) #1

Example that does not compile:

            let randomArray = randomArray(withCapacity: 4096)

Compiler error: “Variable used within its own initial value”
The variable name unfortunately clashes with the function name.

This problem forces the developer to think about an alternative name.
IMHO that’s suboptimal since many times the most canonical naming would be one where these two go by the same name.

It’s not a big problem in practice but I wonder if there are plans to change this?

Thanks,
Michael Gubik


(Austin Zheng) #2

The reason Swift works like this is because you can assign a function value
(independently of calling it) to a variable. So there aren't two separate
namespaces separating function names and variable names.

To wit:

func randomArray(withCapacity capacity: Int) -> [Int] {
    // ....
}

// An array of Ints, the result of calling the function.
let myValue : [Int] = randomArray(withCapacity: 10)
// A function, of type Int -> Array<Int>.
let myFunc : ((Int) -> [Int]) = randomArray

Best,
Austin

···

On Mon, Jan 30, 2017 at 11:37 AM, Michael Gubik via swift-evolution < swift-evolution@swift.org> wrote:

Example that does not compile:

            let randomArray = randomArray(withCapacity: 4096)

Compiler error: “Variable used within its own initial value”
The variable name unfortunately clashes with the function name.

This problem forces the developer to think about an alternative name.
IMHO that’s suboptimal since many times the most canonical naming would be
one where these two go by the same name.

It’s not a big problem in practice but I wonder if there are plans to
change this?

Thanks,
Michael Gubik

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


(Jacob Bandes-Storch) #3

Suppose it were allowed. What should this do?

    let something = randomArray

···

On Mon, Jan 30, 2017 at 11:37 AM, Michael Gubik via swift-evolution < swift-evolution@swift.org> wrote:

Example that does not compile:

            let randomArray = randomArray(withCapacity: 4096)

Compiler error: “Variable used within its own initial value”
The variable name unfortunately clashes with the function name.

This problem forces the developer to think about an alternative name.
IMHO that’s suboptimal since many times the most canonical naming would be
one where these two go by the same name.

It’s not a big problem in practice but I wonder if there are plans to
change this?

Thanks,
Michael Gubik

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


(Jaden Geller) #4

I personally find it kind of weird that `let x = 0; do { let x = x + 1 }` is disallowed but `let x: Int? = 0; if let x = x { }` is allowed. The former case requires you first rename the variable you plan to shadow, inconveniently:

let x = 0
do {
  let tempX = x // ew
  let x = tempX + 1
}
···

On Jan 30, 2017, at 11:56 AM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

This seems like it’s running through the same check that disallows defining and calling a closure

let randomFunc : () -> () = randomFunc()

On Jan 30, 2017, at 2:37 PM, Michael Gubik via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Example that does not compile:

           let randomArray = randomArray(withCapacity: 4096)

Compiler error: “Variable used within its own initial value”
The variable name unfortunately clashes with the function name.

This problem forces the developer to think about an alternative name.
IMHO that’s suboptimal since many times the most canonical naming would be one where these two go by the same name.

It’s not a big problem in practice but I wonder if there are plans to change this?

Thanks,
Michael Gubik

_______________________________________________
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


(Robert Widmann) #5

This seems like it’s running through the same check that disallows defining and calling a closure

let randomFunc : () -> () = randomFunc()

···

On Jan 30, 2017, at 2:37 PM, Michael Gubik via swift-evolution <swift-evolution@swift.org> wrote:

Example that does not compile:

           let randomArray = randomArray(withCapacity: 4096)

Compiler error: “Variable used within its own initial value”
The variable name unfortunately clashes with the function name.

This problem forces the developer to think about an alternative name.
IMHO that’s suboptimal since many times the most canonical naming would be one where these two go by the same name.

It’s not a big problem in practice but I wonder if there are plans to change this?

Thanks,
Michael Gubik

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


(Sean Heber) #6

I used to believe this was a problem, but once I internalized the idea that this ugliness was a signal to choose better variable and property names, it has ceased to be an issue for me and in fact, IMO, has become an asset of the language.

l8r
Sean

···

On Jan 30, 2017, at 3:17 PM, Jaden Geller via swift-evolution <swift-evolution@swift.org> wrote:

I personally find it kind of weird that `let x = 0; do { let x = x + 1 }` is disallowed but `let x: Int? = 0; if let x = x { }` is allowed. The former case requires you first rename the variable you plan to shadow, inconveniently:

let x = 0
do {
  let tempX = x // ew
  let x = tempX + 1
}

On Jan 30, 2017, at 11:56 AM, Robert Widmann via swift-evolution <swift-evolution@swift.org> wrote:

This seems like it’s running through the same check that disallows defining and calling a closure

let randomFunc : () -> () = randomFunc()

On Jan 30, 2017, at 2:37 PM, Michael Gubik via swift-evolution <swift-evolution@swift.org> wrote:

Example that does not compile:

           let randomArray = randomArray(withCapacity: 4096)

Compiler error: “Variable used within its own initial value”
The variable name unfortunately clashes with the function name.

This problem forces the developer to think about an alternative name.
IMHO that’s suboptimal since many times the most canonical naming would be one where these two go by the same name.

It’s not a big problem in practice but I wonder if there are plans to change this?

Thanks,
Michael Gubik

_______________________________________________
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


(Joe Groff) #7

To be honest, I would say that there's no "reason" for this, except as lingering effects of our early "functions have simple names, and arguments have labeled tuple type" model. If we had originally implemented the language with its current (at least aspirational) Smalltalk-ish compound-names model, we probably would have ended up allowing this, since the var and func do formally have different names. The ability to reference a function by only the first segment of its name is likewise legacy of the original model, though it happens to be useful since good naming hygiene encourages different base names for different things to begin with.

-Joe

···

On Jan 30, 2017, at 11:42 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

The reason Swift works like this is because you can assign a function value (independently of calling it) to a variable. So there aren't two separate namespaces separating function names and variable names.


(Derrick Ho) #8

The answer is simple, it becomes ambiguous about whether it should get the
var or the function pointer

Suppose we could do this

let r = 5
func r() {}

If we call r, should we get 5 or should we get ()->()

···

On Mon, Jan 30, 2017 at 4:21 PM Sean Heber via swift-evolution < swift-evolution@swift.org> wrote:

I used to believe this was a problem, but once I internalized the idea
that this ugliness was a signal to choose better variable and property
names, it has ceased to be an issue for me and in fact, IMO, has become an
asset of the language.

l8r
Sean

> On Jan 30, 2017, at 3:17 PM, Jaden Geller via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I personally find it kind of weird that `let x = 0; do { let x = x + 1
}` is disallowed but `let x: Int? = 0; if let x = x { }` is allowed. The
former case requires you first rename the variable you plan to shadow,
inconveniently:
>
> ```
> let x = 0
> do {
> let tempX = x // ew
> let x = tempX + 1
> }
> ```
>
>> On Jan 30, 2017, at 11:56 AM, Robert Widmann via swift-evolution < > swift-evolution@swift.org> wrote:
>>
>> This seems like it’s running through the same check that disallows
defining and calling a closure
>>
>> let randomFunc : () -> () = randomFunc()
>>
>>> On Jan 30, 2017, at 2:37 PM, Michael Gubik via swift-evolution < > swift-evolution@swift.org> wrote:
>>>
>>> Example that does not compile:
>>>
>>> let randomArray = randomArray(withCapacity: 4096)
>>>
>>> Compiler error: “Variable used within its own initial value”
>>> The variable name unfortunately clashes with the function name.
>>>
>>> This problem forces the developer to think about an alternative name.
>>> IMHO that’s suboptimal since many times the most canonical naming
would be one where these two go by the same name.
>>>
>>> It’s not a big problem in practice but I wonder if there are plans to
change this?
>>>
>>>
>>> Thanks,
>>> Michael Gubik
>>>
>>> _______________________________________________
>>> 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

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


(Jacob Bandes-Storch) #9

Although there's no spelling for this...
https://bugs.swift.org/browse/SR-3550

···

On Mon, Jan 30, 2017 at 7:29 PM Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

> On Jan 30, 2017, at 11:42 AM, Austin Zheng via swift-evolution < > swift-evolution@swift.org> wrote:
>
> The reason Swift works like this is because you can assign a function
value (independently of calling it) to a variable. So there aren't two
separate namespaces separating function names and variable names.

To be honest, I would say that there's no "reason" for this, except as
lingering effects of our early "functions have simple names, and arguments
have labeled tuple type" model. If we had originally implemented the
language with its current (at least aspirational) Smalltalk-ish
compound-names model, we probably would have ended up allowing this, since
the var and func do formally have different names. The ability to reference
a function by only the first segment of its name is likewise legacy of the
original model, though it happens to be useful since good naming hygiene
encourages different base names for different things to begin with.

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


(David Hart) #10

The reason Swift works like this is because you can assign a function value (independently of calling it) to a variable. So there aren't two separate namespaces separating function names and variable names.

To be honest, I would say that there's no "reason" for this, except as lingering effects of our early "functions have simple names, and arguments have labeled tuple type" model. If we had originally implemented the language with its current (at least aspirational) Smalltalk-ish compound-names model, we probably would have ended up allowing this, since the var and func do formally have different names. The ability to reference a function by only the first segment of its name is likewise legacy of the original model, though it happens to be useful since good naming hygiene encourages different base names for different things to begin with.

Is there a reason we couldn't push a proposal forward to have the compiler prefer function identifiers when the identifier is followed by a function call syntax? It would be a breaking change, but I'd wager it'd be quite rare: at least rarer than the amount of times this problem has bitten me since Swift 3's grand renaming, forcing me to `self.` prefix the function call (when I can and it's an instance function).

···

On 31 Jan 2017, at 01:59, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 30, 2017, at 11:42 AM, Austin Zheng via swift-evolution <swift-evolution@swift.org> wrote:

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


(Lucas Neiva) #11

It seams like there is discussion to be had, comparing these models:

  [A] functions have simple names, and arguments have labeled tuple type model
  [B] model where we strictly require the labels for referring to n-ary functions (e.g. "insert(cell:, into:)" instead of "insert")

···

On 31 Jan 2017, at 01:59, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

To be honest, I would say that there's no "reason" for this, except as lingering effects of our early "functions have simple names, and arguments have labeled tuple type" model. If we had originally implemented the language with its current (at least aspirational) Smalltalk-ish compound-names model, we probably would have ended up allowing this, since the var and func do formally have different names. The ability to reference a function by only the first segment of its name is likewise legacy of the original model, though it happens to be useful since good naming hygiene encourages different base names for different things to begin with.

---

Example that does not compile:

           let randomArray = randomArray(withCapacity: 4096)

I like [B] because it does solve cases of ambiguity, where only using the base-name of the func causes the "Variable used within its own initial value” described by Michael.

What are some advantages of [A]? I assume that tuple splatting (i.e. passing a tuple of args when calling a n-ary function) is one of them, or is that not related?


(Tino) #12

Afaics the motivation has been explained in detail, but actually, you even can declare such a variable as long as it has its own scope:

class Test {
  func f(i: Int) {
    print(i)
  }

  func g() {
    let f = 1 // hey, works!
    print(f)
    print(self.f(i:f)) // works as well
  }

  var f: (Int) -> Void = f // huh?
}


(Jaden Geller) #13

Not quite—you can already shadow function names:

func f() { print("hi") }
do {
    let f = { print("bye") }
    f()
}

You can refer to shadowed variables within their initial value—function or not—within a guard let or if let:

func f() -> (() -> ())? { return { print("hi")} }
do {
    guard let f = f() else { fatalError() }
    f()
}

BUT, you cannot refer to shadowed variables within their initial value otherwise:

func f() { print("hi") }
do {
    let f = { f(); f() } // ERROR!!!
    f()
}

This is inconsistent IMO.

···

On Jan 30, 2017, at 5:17 PM, Derrick Ho <wh1pch81n@gmail.com> wrote:

The answer is simple, it becomes ambiguous about whether it should get the var or the function pointer

Suppose we could do this

let r = 5
func r() {}

If we call r, should we get 5 or should we get ()->()

On Mon, Jan 30, 2017 at 4:21 PM Sean Heber via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I used to believe this was a problem, but once I internalized the idea that this ugliness was a signal to choose better variable and property names, it has ceased to be an issue for me and in fact, IMO, has become an asset of the language.

l8r
Sean

> On Jan 30, 2017, at 3:17 PM, Jaden Geller via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> I personally find it kind of weird that `let x = 0; do { let x = x + 1 }` is disallowed but `let x: Int? = 0; if let x = x { }` is allowed. The former case requires you first rename the variable you plan to shadow, inconveniently:
>
> ```
> let x = 0
> do {
> let tempX = x // ew
> let x = tempX + 1
> }
> ```
>
>> On Jan 30, 2017, at 11:56 AM, Robert Widmann via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>> This seems like it’s running through the same check that disallows defining and calling a closure
>>
>> let randomFunc : () -> () = randomFunc()
>>
>>> On Jan 30, 2017, at 2:37 PM, Michael Gubik via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>
>>> Example that does not compile:
>>>
>>> let randomArray = randomArray(withCapacity: 4096)
>>>
>>> Compiler error: “Variable used within its own initial value”
>>> The variable name unfortunately clashes with the function name.
>>>
>>> This problem forces the developer to think about an alternative name.
>>> IMHO that’s suboptimal since many times the most canonical naming would be one where these two go by the same name.
>>>
>>> It’s not a big problem in practice but I wonder if there are plans to change this?
>>>
>>>
>>> Thanks,
>>> Michael Gubik
>>>
>>> _______________________________________________
>>> 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 <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


(Joe Groff) #14

IMO, the way to spell `foo` with no arguments is just `foo`. If we strictly required the labels for referring to n-ary functions, that would make it unambiguous…

-Joe

···

On Jan 30, 2017, at 7:34 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

Although there's no spelling for this... https://bugs.swift.org/browse/SR-3550


(Jacob Bandes-Storch) #15

You said "The ability to reference a function by only the first segment of
its name is likewise legacy of the original model..." — how else could you
refer to a nullary function? Even if labels were required for naming
(>0)-ary functions, there's still ambiguity between a nullary function and
a variable.

···

On Mon, Jan 30, 2017 at 7:54 PM Joe Groff <jgroff@apple.com> wrote:

> On Jan 30, 2017, at 7:34 PM, Jacob Bandes-Storch <jtbandes@gmail.com> > wrote:
>
> Although there's no spelling for this...
https://bugs.swift.org/browse/SR-3550

IMO, the way to spell `foo` with no arguments is just `foo`. If we
strictly required the labels for referring to n-ary functions, that would
make it unambiguous…

-Joe


(Tino) #16

It seams like there is discussion to be had, comparing these models:

  [A] functions have simple names, and arguments have labeled tuple type model
  [B] model where we strictly require the labels for referring to n-ary functions (e.g. "insert(cell:, into:)" instead of "insert")

I like [B] because it does solve cases of ambiguity, where only using the base-name of the func causes the "Variable used within its own initial value” described by Michael.

What are some advantages of [A]? I assume that tuple splatting (i.e. passing a tuple of args when calling a n-ary function) is one of them, or is that not related?

Imho B has drawbacks which count as advantages for A:

- More typing (obvious, although not that terrible)

- Can easily be confused with an actual function call (imho "(" is tightly coupled with the idea of "ah, that's a function that is called"):

func f(_ arg: Int) -> Int {
  print(arg)
  return 0
}

func f(arg: Int) -> Int {
  print("Not", arg)
  return arg
}

let arg = 1

let outFunc = f(arg:)
let outInt = f(arg)

- May look odd (especially if you are used to functions in math)

func g(_ a: Int, _ b: Int) -> Int {
  return a + b
}

let looksLikePearl = g(:, :slight_smile: // "Expected expression in list of expressions" - compiler doesn't like it either :wink:

···

Am 31.01.2017 um 01:59 schrieb Joe Groff via swift-evolution <swift-evolution@swift.org>:

The ability to reference a function by only the first segment of its name is likewise legacy of the original model, though it happens to be useful since good naming hygiene encourages different base names for different things to begin with.

+1, hope the short syntax stays the preferred choice when there is no ambiguity.

- Tino


(Xiaodi Wu) #17

Just left a comment on the bug; it's clear we need some sort of new syntax,
and I'd like to throw out `foo(:)` as a candidate, by analogy with `[:]`
being an empty dictionary.

···

On Mon, Jan 30, 2017 at 22:04 Jacob Bandes-Storch via swift-evolution < swift-evolution@swift.org> wrote:

You said "The ability to reference a function by only the first segment of
its name is likewise legacy of the original model..." — how else could you
refer to a nullary function? Even if labels were required for naming
(>0)-ary functions, there's still ambiguity between a nullary function and
a variable.
On Mon, Jan 30, 2017 at 7:54 PM Joe Groff <jgroff@apple.com> wrote:

> On Jan 30, 2017, at 7:34 PM, Jacob Bandes-Storch <jtbandes@gmail.com> > wrote:
>
> Although there's no spelling for this...
https://bugs.swift.org/browse/SR-3550

IMO, the way to spell `foo` with no arguments is just `foo`. If we
strictly required the labels for referring to n-ary functions, that would
make it unambiguous…

-Joe

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


(David Sweeris) #18

Works for me.

- Dave Sweeris

···

On Jan 30, 2017, at 8:14 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Just left a comment on the bug; it's clear we need some sort of new syntax, and I'd like to throw out `foo(:)` as a candidate, by analogy with `[:]` being an empty dictionary.