On shadowing vs overloading #952
Replies: 6 comments 9 replies
-
I find that, given the definition of “parent scope,” this is rather surprising, because two siblings need not have the same parent.
For now, though, I'll work with it. Oh, you change the definitions further down. That's confusing. If you think you have an improved set, please just replace the old ones. |
Beta Was this translation helpful? Give feedback.
-
I think there's a simpler way to describe the semantics that I, at least, want. A scope is a mapping between names and sets of declarations. struct Scope {
/// A mapping from a name to the set of declarations of that name in this scope.
typealias LookupTable = [UnqualifiedName: [Declaration]]
/// The declarations in this scope that come from the module currently being compiled
let currentModule: LookupTable
/// The other declarations in this scope
let otherModules: LookupTable
/// The nominal scope that owns declarations made lexically in this scope, if any.
indirect let associatedNominalScope: Scope?
} Here visibility is omitted but in any context, you can imagine that invisible declarations are not stored in the scope's There are two kinds of scopes, nominal and lexical. A nominal scope is an entity with a name, like a module or type. Lexical scopes are unnamed, like the body of a IIUC, this is entirely about unqualified name lookup. That is, a name in an expression not preceded by My proposed algorithm: /// Returns the declarations named by `n` when it is written without qualification in `lexicalContext`,
/// the surrounding lexical scopes from innermost to outermost.
func lookupUnqualified(_ n: UnqualifiedName, from lexicalContext: [Scope]) -> [Declaration] {
for s in lexicalContext {
let r = (s.associatedNominalScope ?? s).localDeclarations(of: n, visibleFrom: lexicalContext)
if !r.isEmpty { return r }
}
return []
}
extension Scope {
fun localDeclarations(of n: UnqualifiedName, visibleFrom lexicalContext: [Scope]) -> [Declarations] {
currentModule[n] ?? otherModules[n] ?? []
}
} The basic rules upheld are:
Examples:
|
Beta Was this translation helpful? Give feedback.
-
True.
OK, that's easy to answer in my preferred semantics. Let me take another stab at that in a separate post.
I don't think you do… because I don't think Swift has that feature 😉 IIUC, access control like
Because a declaration in each file in the module is… in the module's scope? If the module name is |
Beta Was this translation helpful? Give feedback.
-
Attempt no. 2 to describe my rules.For context, I want to uphold a principle of modularity. That is, an access from module This is still mostly about name lookup. I'm going to try to state some rules instead of spelling out an algorithm to implement them. I think this list of rules is probably slightly incomplete, but I hope we can amend it until it covers everything. I believe it should also be extended to cover conformances.
Let me know what you think. |
Beta Was this translation helpful? Give feedback.
-
I'm starting to wonder if perhaps we'd be better off simply requiring an
The problem here is that because the extension has higher priority (under either Dave or my rules), The Some examples:
|
Beta Was this translation helpful? Give feedback.
-
Following the meeting discussion on Aug. 7th, here is another attempt at specifying the overloading/shadowing situation. The principle we hope to maintain are:
With that being said, here are the rules: Scopes and relationships
Example:
The following statements hold:
Nominal scopes
Scope exposition
Shadowing
Name lookupName lookup in a nominal scope
|
Beta Was this translation helpful? Give feedback.
-
I'm starting this thread to describe my proposal for the shadowing/overloading rules of Hylo.
Background
From the (still relevant part of) the specification:
Here are some example of names:
foo
(a stem without anything else)infix+
(an operator notationinfix
with a stem+
)bar(ham:viz:).let
(a stembar
with labelsham:viz:
and an introducerlet
)Note that given these definitions,
first_index(of:)
andfirst_index(where:)
are not the same name!Next are the definitions of scopes and declarations spaces. We should probably add a notion of depth to the sibling relationship because we don't want the scope of a nested extension to be the same kind of sibling of the original type declaration, so I've stroke through what I think should be overridden.
[Note: in the current implementation, files are also scopes. I think we should rather say that a file is implicitly a namespace but that is an ad-hoc discussion.]
I propose we override 4-5 as such:
[Note: these amended definitions imply that conformances at global scope are bridged but no longer siblings.]
Tentative definitions of shadowing and overloading
These definitions favor shadowing, only allowing overloading to occur in sibling scopes. Rule 1 describes when overloading occurs. Rule 2 describes when shadowing occurs. Rule 3 prevents overloading across non-sibling scopes [Note: scopes related by a aunt/niece relationship cause shadowing].
For example, it means that this program is legal:
But this program isn't:
Extensions
Overloading is allowed to occur in sibling scopes, meaning that this program is legal:
However, the same program would be illegal if
A
's primary declaration came from another module.There are a few of potential issues with this setup. First, because source files are their own scope, it means extensions of a type in different source files of the same module can't add overloads, which might be too restrictive. I see two ways to relax this rule:
Second, this setup doesn't let you export overloads of an imported type, which may be an issue. For example, you can't write this program:
Lastly, this setup doesn't let you add specialization points in nested scopes:
The error occured because
foo
got shadowed but its new defintion is conditional. We may be able to fix this issue by saying that shadowing is conditional in this case.Conformances
I think that shadowing should not apply to implementations participating in a conformance when methods of that conformance is used, even in monomorphizable contexts. My goal is to avoid introducing differences between the semantics of monomorphized and existentialized code.
Beta Was this translation helpful? Give feedback.
All reactions