Skip to content
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

Generic parameterized impls (details 5) #920

Merged
merged 40 commits into from
Dec 9, 2021
Merged

Generic parameterized impls (details 5) #920

merged 40 commits into from
Dec 9, 2021

Conversation

josh11b
Copy link
Contributor

@josh11b josh11b commented Oct 27, 2021

There are cases where an impl definition should apply to more than a single type and interface combination. The solution is to parameterize the impl definition, so it applies to a family of types, interfaces, or both. This includes:

  • Declare an impl for a parameterized type, which may be external or declared out-of-line.
    external impl [T:! Type] Vector(T) as Iterable { ... }
    external impl Vector(T:! Type) as Iterable { ... }
    
  • "Conditional conformance" where a parameterized type implements some interface if the parameter to the type satisfies some criteria, like implementing the same interface.
    external impl [T:! Type] Pair(T, T) as Foo(T) { ... }
    class Array(T:! Type, template N:! Int) {
      impl [P:! Printable] Array(P, N) as Printable { ... }
      impl Array(P:! Printable, N) as Printable { ... }
    }
    
  • "Blanket" impls where an interface is implemented for all types that implement another interface, or some other criteria beyond being a specific type.
    external impl [T:! Ordered] T as PartiallyOrdered { ... }
    
  • "Wildcard" impls where a family of interfaces are implemented for single type.
    class BigInt {
      external impl [T:! ImplicitAs(i32)] as AddTo(T) { ... }
      external impl as AddTo(T:! ImplicitAs(i32)) { ... }
    }
    external impl [T:! ImplicitAs(i32)] BigInt as AddTo(T) { ... }
    external impl BigInt as AddTo(T:! ImplicitAs(i32)) { ... }
    

In addition to a syntax for defining parameterized impls, we need rules for coherence:

  • Orphan rules that ensure that impls are imported in any code that might use it.
  • We need overlap rules that pick a specific impl when more than one impl declaration matches a specific query about whether a type implements an interface.

@josh11b josh11b added the proposal A proposal label Oct 27, 2021
@josh11b josh11b added this to Draft in Proposals via automation Oct 27, 2021
@josh11b josh11b requested a review from a team October 27, 2021 20:38
@google-cla google-cla bot added the cla: yes PR meets CLA requirements according to bot. label Oct 27, 2021
@josh11b josh11b changed the title Generic blanket impls and access control (details 4) Generic blanket impls(details 5) Oct 29, 2021
@josh11b josh11b changed the title Generic blanket impls(details 5) Generic blanket impls (details 5) Oct 29, 2021
@josh11b josh11b changed the title Generic blanket impls (details 5) Generic parameterized impls (details 5) Nov 2, 2021
@josh11b josh11b requested a review from a team as a code owner November 10, 2021 23:48
@github-actions github-actions bot added the proposal rfc Proposal with request-for-comment sent out label Nov 10, 2021
docs/design/generics/details.md Outdated Show resolved Hide resolved
docs/design/generics/details.md Outdated Show resolved Hide resolved
docs/design/generics/details.md Outdated Show resolved Hide resolved
docs/design/generics/details.md Show resolved Hide resolved
docs/design/generics/details.md Outdated Show resolved Hide resolved
docs/design/generics/details.md Outdated Show resolved Hide resolved
docs/design/generics/overview.md Outdated Show resolved Hide resolved
proposals/p0920.md Outdated Show resolved Hide resolved
proposals/p0920.md Outdated Show resolved Hide resolved
proposals/p0920.md Outdated Show resolved Hide resolved
Copy link
Contributor

@zygoloid zygoloid left a comment

Choose a reason for hiding this comment

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

Thanks, this looks great! No further comments from me.

Copy link
Contributor

@zygoloid zygoloid left a comment

Choose a reason for hiding this comment

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

Please go ahead.

@josh11b josh11b merged commit 2f844d9 into carbon-language:trunk Dec 9, 2021
Proposals automation moved this from RFC to Accepted Dec 9, 2021
@josh11b josh11b deleted the blanket branch December 9, 2021 22:29
@github-actions github-actions bot added proposal accepted Decision made, proposal accepted and removed proposal rfc Proposal with request-for-comment sent out labels Dec 9, 2021
chandlerc pushed a commit that referenced this pull request Jun 28, 2022
There are cases where an impl definition should apply to more than a single type and interface combination. The solution is to parameterize the impl definition, so it applies to a family of types, interfaces, or both. This includes:

-   Declare an impl for a parameterized type, which may be external or declared out-of-line.
    ```
    external impl [T:! Type] Vector(T) as Iterable { ... }
    external impl Vector(T:! Type) as Iterable { ... }
    ```
-   "Conditional conformance" where a parameterized type implements some interface if the parameter to the type satisfies some criteria, like implementing the same interface.
    ```
    external impl [T:! Type] Pair(T, T) as Foo(T) { ... }
    class Array(T:! Type, template N:! Int) {
      impl [P:! Printable] Array(P, N) as Printable { ... }
      impl Array(P:! Printable, N) as Printable { ... }
    }
    ```
-   "Blanket" impls where an interface is implemented for all types that implement another interface, or some other criteria beyond being a specific type.
    ```
    external impl [T:! Ordered] T as PartiallyOrdered { ... }
    ```
-   "Wildcard" impls where a family of interfaces are implemented for single type.
    ```
    class BigInt {
      external impl [T:! ImplicitAs(i32)] as AddTo(T) { ... }
      external impl as AddTo(T:! ImplicitAs(i32)) { ... }
    }
    external impl [T:! ImplicitAs(i32)] BigInt as AddTo(T) { ... }
    external impl BigInt as AddTo(T:! ImplicitAs(i32)) { ... }
    ```

In addition to a syntax for defining parameterized impls, we need rules for coherence:

-   Orphan rules that ensure that impls are imported in any code that might use it.
-   We need overlap rules that pick a specific impl when more than one impl declaration matches a specific query about whether a type implements an interface.

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
github-merge-queue bot pushed a commit that referenced this pull request Aug 2, 2023
This reflects changes from a number of approved proposals:
- #920 : concrete statements about orphan and overlap in Carbon
- #2138 : "generic" -> "checked generic", "template" -> "template
generic"
- #2188 : binding patterns are forbidden in type position
- #2360 : "type", "facet type", "facet". Note: I am not using the term
"generic type" from #2360 since that meaning conflicts with the
generally accepted meaning of "generic type" of a type with a
compile-time parameter.
- #2760 / #2770 : internal/external impl -> extending impl
- #2964 : "symbolic constant" and "template constant"

---------

Co-authored-by: Geoff Romer <gromer@google.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes PR meets CLA requirements according to bot. proposal accepted Decision made, proposal accepted proposal A proposal
Projects
No open projects
Proposals
Accepted
Development

Successfully merging this pull request may close these issues.

None yet

2 participants