-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
when are facet types equal? #2409
Comments
LGTM FWIW... Any concerns @josh11b or others looking at generics? |
It seems like it would be simplest to say that two facet types are equal if and only if each is a (non-strict) subtype of the other. Is this issue also asking whether to use a structural, lexical-nominal, or semantic-nominal rule for the subtyping relation, or has that question already been settled? Are the specification and implementation challenges different for the subtyping relation than for the equality relation? |
I think it would be useful to consider when this issue will come up.
It seems much more common to need to worry about subsumption / subtyping of facet types than equality, since that comes up when calling one generic function from another. For this reason, #2409 (comment) makes a lot of sense to me: define the edge case thing in terms of the common thing we are going to care a lot more about. This leads to implementation simplicity and less for users to learn. I think this leads to using a structural rule. My expectation when writing up the rules for generics was that structural things like named constraints would be compared structurally, because that seems significantly more natural to me. Interfaces create new "atoms" that are nominal. I talked about this in #syntax on 2022-10-27. |
Just want to check back in on this issue as a bunch of the terminology and other design questions in the space resolved -- are we ready to pin this down? |
Terminology-wise, this is talking about "facet types" in agreement with the definition given in #2360 . From https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p2360.md#terminology :
|
I wonder if #2409 (comment) provides a way to get the implementation simplicity of the nominal semantic rule without its downsides. Specifically, saying that I do think that the implementation challenges raised for the structural approach are concerning. Structural equality rules have been very difficult to come up with for complex structures, and I'm worried about exactly that case here. One nice thing about the subtyping aspect is that it may make it easy to have it both ways: regardless of whether |
Here is an example that reflects my understanding of the question.
Is this correct? |
Discussed in open discussion today |
The conclusion from the open discussion that @josh11b linked to is that we want a structural rule despite the implementation costs. That seems to give the least surprising behavior across the examples we considered. The rules we preferred are as follows:
This means that:
We had an open question as to whether we should allow aliases in named constraints, given the complexity they would add to determining equality for facet types, but it doesn't seem necessary to decide that in order to answer the question in this issue. |
Marking as decided with this comment: #2409 (comment) |
I'm reopening this based on recent discussion. Because we support incomplete interface types and, more seriously, incomplete named constraint types, we cannot provide the rule we described in the previous comment in general because we cannot tell whether an incomplete facet type is a subtype or supertype of another facet type -- and we need to be able to tell whether any two given One option that we might want to consider is to distinguish between nominal facet types (interfaces and named constraints, which may be complete or incomplete) and structural facet types (formed by
Another option might be to use one of the lexical rules described in the first comment of this issue. |
We then discussed relaxing when facet types would be required to be complete further in order to allow things like For each facet type we can eagerly form a canonical type, which is normalized as much as possible while treating named facet types as opaque. And then separately we lazily form a resolved facet type, as described by the Rewrite constraint resolution section, which requires all of those named facet types to be defined, and expands them to their corresponding structural facet type. And we do the lazy step when processing an |
Canonicalization rules: For
Normalization and qualification of designators in
Notes:
Interaction between multiple
The result of this is facet types have a canonical form:
An interface or named constraint
|
After some reflection and discussion, @zygoloid and I decided:
|
Summary of issue:
As described in the generics design, there is a subtyping relationship between facet types when one has a subset of the constraints of another. But it's not clear when facet types are equal: should two facet types with the same set of constraints and the same lookup behavior be "the same", or merely be two different types that have the same behavior?
Details:
One place where this comes up is with the definition of the type
type
. For example:The use of an expression of type
X
after a:
causes us to look forImplicitAs(type)
, which raises the question of whethertype
is the same value asIsThisTheSameAsType
, or a different value that has the same behavior.Any other information that you want to share?
We could use a structural rule that says that two facet types are the same value if they have the same set of constraints and the same lookup behavior. This may be challenging to specify in a way that implementations agree on, for example because the facet type may have an unresolved set of rewrites, or because it would matter whether vacuous constraints like
.Self is type
are retained or discarded, or because this would require us to precisely define what it means for two facet types to have the same lookup behavior. This is the approach that explorer currently takes, with a fairly arbitrary set of decisions for the implementation questions.We could use a lexical nominal rule that says that two facet types are the same value if they were created in the same way (naming the same interface, combining constraints with
&
in the same order, etc). That rule may also be challenging to support, because it would likely require implementations to track the provenance of each facet type.We could use a more semantic nominal rule that says that each
&
orwhere
evaluation creates a unique new facet type, as does eachconstraint
orinterface
declaration. That approach seems to provide both a reasonable level of simplicity for implementations and an easily understandable user model. This would mean thatIsThisTheSameAsType
is not the same astype
, and nor istype & type
ortype where .Self is type
. That's the approach that seems most promising to me.The text was updated successfully, but these errors were encountered: