Skip to content

Add spec for intersection types #5233

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

Merged
merged 5 commits into from
Oct 16, 2018
Merged

Conversation

liufengyun
Copy link
Contributor

Add spec for intersection types

## Syntax

Syntactically, an intersection type `S & T` is similar to an infix type,
where the infix operator is `&`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's expand on this a little bit:

... where the infix operator is the identifier &. & is treated as a soft keyword. That is, it is a normal identifier with the usual precedence. But a type of the form A & B is always recognized as an intersection type, without trying to resolve &.

```
Type ::= ...| InfixType
InfixType ::= RefinedType {id [nl] RefinedType}
RefinedType ::= WithType {[nl] Refinement}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd drop productions for RefinedType and WithType, since WithTypes will be removed, adding them here is confusing.


The type of `children` in `A & B` is the intersection of `children`'s
type in `A` and its type in `B`, which is `List[A] & List[B]`. This
can be further simplified to `List[A & B]` because `List` is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By what rule? I think it would be good to specify the rule for this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I proposed a rule in the subtyping section

Copy link
Contributor Author

@liufengyun liufengyun Oct 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems List[A & B] <: List[A] & List[B] can be derived by the normal subtyping rule for type constructors, no more rules required.

    A <: A                        B <: B
  ----------                     ---------
  A & B <: A                     A & B < B
----------------------     ----------------------
List[A & B] <: List[A]     List[A & B] <: List[B]
--------------------------------------------------
      List[A & B] <: List[A] & List[B]

If C is contravariant:

    A <: A                        B <: B
  ----------                     ---------
  A <: A | B                     B < A | B
----------------------     ----------------------
C[A | B] <: C[A]              C[A | B] <: C[B]
--------------------------------------------------
            C[A | B] <: C[A] & C[B]

I agree, it is good to document them.

----------------
A & B <: T
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If C is a type constructor, the join C[A] & C[B] is simplified by pulling the intersection inside the constructor, using the following rules:

  • If C is covariant, C[A] & C[B] = C[A & B]
  • If C is contravariant, C[A] & C[B] = C[A | B]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh ... I think my comment above should have been a follow up to this ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. The derivation provides partial justification for the simplification, as we cannot derive in the other direction.

I tried to find examples where the rules are unsound, but failed. It seems the other direction can be justified informally. @odersky mentioned some theoretical work is needed here based on DOT.


## Type Checking

The type `S & T` represents values that are of the type `S` and `T` at the same time.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would leave this material in the main page.

class C extends A with B {
def children: List[A & B] = ???
}
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Integrate the whole type checking section in the main page.

@odersky odersky assigned liufengyun and unassigned odersky Oct 12, 2018
Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now. Thanks!

@odersky odersky merged commit 2063e85 into scala:master Oct 16, 2018

- If `C` is covariant, `C[A] & C[B] ~> C[A & B]`
- If `C` is contravariant, `C[A] & C[B] ~> C[A | B]`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does the "simplified" terminology and the ~> come from? Intuitively it makes sense, but seems redundant with the typing rules stating the same thing immediately below.

@allanrenucci allanrenucci deleted the fix-intersection branch October 17, 2018 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants