Notional bundles #1553
Replies: 2 comments 1 reply
-
The point of the bundle is to create one entity in the language, not necessarily to have one syntactic mechanism to do so. Does the documentation for one access apply to the other one, for example? |
Beta Was this translation helpful? Give feedback.
-
I don't think this is right. It is precisely the second syntax, the one that lets us definitively identify members of a bundle that are not proximate in the source, that reduces overload resolution. Yes, it is a significant burden to have a second syntax. My only point is: if we happen to need a second syntax, that doesn't entirely undermine the value of bundles, which is “one may question the purpose…” seems to imply.
You might be missing my point. Clearly we want the same documentation to apply to all parts of a bundle, no matter where they are written (for presentation purposes the doc webpage might actually say "extends |
Beta Was this translation helpful? Give feedback.
-
An interesting problem came up recently when I tried to identify the cause of a bug in name resolution. Consider the following program:
This program will currently report an ambiguity error in the main function, complaining that there are two valid candidates for the subscript to apply.
There are good reasons to define the different variants of a subscript in different extensions. For example, one may want to write a conditional conformance to
MutableCollection
for a type that unconditionally conforms toCollection
. The former trait requires aninout
subscript while the latter only requires alet
variant. So we may be tempted to write:Note that the same arguments can be applied to method bundles, not only subscripts.
Name resolution normally expects that all variants are gather in the same bundle declaration. That way, it can bind a name to that bundle and delay the selection of a particular variant until after we've gather enough flow-sensitive information (typically during IR lowering or analysis) to make an informed decision. The problem in the above examples is that name resolution is forced to make a choice before this information has been gathered. Relying on the presence of a mutation marker is not good enough because it wouldn't help us distinguish between
let
andsink
orset
andinout
variants.A better approach to solve this problem is to assume the existence of a "notional" bundle that gathers all the variant definitions, no matter where they are declared. This way, name resolution could bind names to this notional bundle and let a later phase of the compiler decide which variant must be used, as with regular bundles. One challenge with this approach is to determine how variants should be gathered.
I note that this issue is revealing a weakness in the design of bundles. One of the original goals was precisely to make this determination obvious, by gathering related definitions under the same syntactic element. One may therefore question the purpose of a bundle if we need another procedure to gather related definitions anyway.
As @dabrahams pointed out on Slack, there are likely two ways to identify related variants:
A
's conformance toMutableCollection
in the above example).One complication with either approach is about the constraints under which different variants are defined. If those constraints do not match, the selection of a variant later on may require another type checking pass to determine whether a particular choice is well-typed. For example:
A use of
inout
onA<B>
variant is ill-typed because it does not satisfy the condition of the extension in which this variant is defined. The difficulty here is to decide what name resolution is supposed to do. If it conservatively requires all possible constraints of the notional bundle, then it will incorrectly make the use of thelet
variant illegal in the above example. But if those constraints are not upheld, the compiler will incorrectly accept the illegal use of theinout
variant.Beta Was this translation helpful? Give feedback.
All reactions