[Discussion] File-level declarations having highest priority for shadowing

I've filed this previously as a compiler bug, but was told to discuss this here (https://bugs.swift.org/browse/SR-1772\).

Motivation:

Consider the following code:

private func _validateAccount(name: String, existingAccounts: [Account]) -> Bool {
    // Logic goes here...
}

class MyController {
    private func _validateAccount(name: String) -> Bool {
        let accounts = self.accounts

  // Error: Extra argument 'existingAccounts' in call
        return _validateAccount(name, existingAccounts: accounts)
    }
}

_validateAccount(name:, existingAccounts:) is declared at file-level since it is used in two separate controllers (my example comes from an app with accounts and the check is done during creation + when renaming) and then a similar method (with less arguments) is declared on the controllers.

Currently, the compiler gives an error about ambiguous use of _validateAccount, since it's declared on MyController as well which is taking precedence, even though the number of arguments is different (and the compiler is only checking base names, not arguments).

As Jordan Rose mentioned in a comment to my report, solution to this is to specify the function using Module._validateAccount, but this is not applicable to Playgrounds.

This is partially an issue of the ongoing discussion of various name collisions between modules, but in this particular case, it's one single file.

I propose that file-level symbols take precedence over any reference to current type's members, unless explicit self is specified, or at least when it comes to calling a method, the type checker goes up the scope hierarchy to see if there isn't a function satisfying the arguments.

I can see how this is a problem, but I don't like this solution for the
same reasoning that Jordan provided in the bug. Namely, the general rule is
that the inner scope shadows the outer scope. This would be a very strange
exception that you're proposing.

I'd rather cope temporarily with the current limitation, which as you
mentioned has a workaround everywhere except in Playgrounds; in
Playgrounds, there isn't any reason why you couldn't just rename one or the
other.

···

On Mon, Jun 20, 2016 at 13:55 Charlie Monroe via swift-evolution < swift-evolution@swift.org> wrote:

I've filed this previously as a compiler bug, but was told to discuss this
here (https://bugs.swift.org/browse/SR-1772\).

Motivation:

Consider the following code:

private func _validateAccount(name: String, existingAccounts: [Account])
-> Bool {
    // Logic goes here...
}

class MyController {
    private func _validateAccount(name: String) -> Bool {
        let accounts = self.accounts

// Error: Extra argument 'existingAccounts' in call
        return _validateAccount(name, existingAccounts: accounts)
    }
}

_validateAccount(name:, existingAccounts:) is declared at file-level since
it is used in two separate controllers (my example comes from an app with
accounts and the check is done during creation + when renaming) and then a
similar method (with less arguments) is declared on the controllers.

Currently, the compiler gives an error about ambiguous use of
_validateAccount, since it's declared on MyController as well which is
taking precedence, even though the number of arguments is different (and
the compiler is only checking base names, not arguments).

As Jordan Rose mentioned in a comment to my report, solution to this is to
specify the function using Module._validateAccount, but this is not
applicable to Playgrounds.

This is partially an issue of the ongoing discussion of various name
collisions between modules, but in this particular case, it's one single
file.

I propose that file-level symbols take precedence over any reference to
current type's members, unless explicit self is specified, or at least when
it comes to calling a method, the type checker goes up the scope hierarchy
to see if there isn't a function satisfying the arguments.

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

IMHO file-level scope *is* special. Aside from the fact that some declarations (e.g. protocols) are only valid at file-level scope, the way I see it, it's a scope where you have *global* symbols to the file - i.e. they should be available *globally* anywhere within the file.

I undestand that this goes against the overall hierarchy of shadowing, though, which is why I've proposed an alternative: the compiler shouldn't (in case of invoking methods) just check the base name, but it should do a more thorough search, looking at the arguments as well. Just like when you're overloading a method.

···

On Jun 20, 2016, at 8:59 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

I can see how this is a problem, but I don't like this solution for the same reasoning that Jordan provided in the bug. Namely, the general rule is that the inner scope shadows the outer scope. This would be a very strange exception that you're proposing.

I'd rather cope temporarily with the current limitation, which as you mentioned has a workaround everywhere except in Playgrounds; in Playgrounds, there isn't any reason why you couldn't just rename one or the other.
On Mon, Jun 20, 2016 at 13:55 Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I've filed this previously as a compiler bug, but was told to discuss this here (https://bugs.swift.org/browse/SR-1772\).

Motivation:

Consider the following code:

private func _validateAccount(name: String, existingAccounts: [Account]) -> Bool {
    // Logic goes here...
}

class MyController {
    private func _validateAccount(name: String) -> Bool {
        let accounts = self.accounts

  // Error: Extra argument 'existingAccounts' in call
        return _validateAccount(name, existingAccounts: accounts)
    }
}

_validateAccount(name:, existingAccounts:) is declared at file-level since it is used in two separate controllers (my example comes from an app with accounts and the check is done during creation + when renaming) and then a similar method (with less arguments) is declared on the controllers.

Currently, the compiler gives an error about ambiguous use of _validateAccount, since it's declared on MyController as well which is taking precedence, even though the number of arguments is different (and the compiler is only checking base names, not arguments).

As Jordan Rose mentioned in a comment to my report, solution to this is to specify the function using Module._validateAccount, but this is not applicable to Playgrounds.

This is partially an issue of the ongoing discussion of various name collisions between modules, but in this particular case, it's one single file.

I propose that file-level symbols take precedence over any reference to current type's members, unless explicit self is specified, or at least when it comes to calling a method, the type checker goes up the scope hierarchy to see if there isn't a function satisfying the arguments.

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

IMHO file-level scope *is* special. Aside from the fact that some
declarations (e.g. protocols) are only valid at file-level scope, the way I
see it, it's a scope where you have *global* symbols to the file - i.e.
they should be available *globally* anywhere within the file.

I undestand that this goes against the overall hierarchy of shadowing,
though, which is why I've proposed an alternative: the compiler shouldn't
(in case of invoking methods) just check the base name, but it should do a
more thorough search, looking at the arguments as well. Just like when
you're overloading a method.

I could support a proposal for that alternative.

···

On Mon, Jun 20, 2016 at 2:17 PM, Charlie Monroe <charlie@charliemonroe.net> wrote:

On Jun 20, 2016, at 8:59 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

I can see how this is a problem, but I don't like this solution for the
same reasoning that Jordan provided in the bug. Namely, the general rule is
that the inner scope shadows the outer scope. This would be a very strange
exception that you're proposing.

I'd rather cope temporarily with the current limitation, which as you
mentioned has a workaround everywhere except in Playgrounds; in
Playgrounds, there isn't any reason why you couldn't just rename one or the
other.
On Mon, Jun 20, 2016 at 13:55 Charlie Monroe via swift-evolution < > swift-evolution@swift.org> wrote:

I've filed this previously as a compiler bug, but was told to discuss
this here (https://bugs.swift.org/browse/SR-1772\).

Motivation:

Consider the following code:

private func _validateAccount(name: String, existingAccounts: [Account])
-> Bool {
    // Logic goes here...
}

class MyController {
    private func _validateAccount(name: String) -> Bool {
        let accounts = self.accounts

// Error: Extra argument 'existingAccounts' in call
        return _validateAccount(name, existingAccounts: accounts)
    }
}

_validateAccount(name:, existingAccounts:) is declared at file-level
since it is used in two separate controllers (my example comes from an app
with accounts and the check is done during creation + when renaming) and
then a similar method (with less arguments) is declared on the controllers.

Currently, the compiler gives an error about ambiguous use of
_validateAccount, since it's declared on MyController as well which is
taking precedence, even though the number of arguments is different (and
the compiler is only checking base names, not arguments).

As Jordan Rose mentioned in a comment to my report, solution to this is
to specify the function using Module._validateAccount, but this is not
applicable to Playgrounds.

This is partially an issue of the ongoing discussion of various name
collisions between modules, but in this particular case, it's one single
file.

I propose that file-level symbols take precedence over any reference to
current type's members, unless explicit self is specified, or at least when
it comes to calling a method, the type checker goes up the scope hierarchy
to see if there isn't a function satisfying the arguments.

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