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

Implicit/inferred generic type constraints #809

Closed
josh11b opened this issue Sep 3, 2021 · 9 comments
Closed

Implicit/inferred generic type constraints #809

josh11b opened this issue Sep 3, 2021 · 9 comments
Labels
leads question A question for the leads team

Comments

@josh11b
Copy link
Contributor

josh11b commented Sep 3, 2021

Question: Should the following compile, or should the compiler require that the user explicitly list all of HashSet's requirements for KeyType?

class HashSet(KeyType:! Hashable & HasEquals & Movable);
fn Contains[KeyType:! Type](needle: KeyType, haystack: HashSet(KeyType)) -> Bool;
fn Print[KeyType:! Printable](set_to_print: HashSet(KeyType));
  • Swift supports this: 1, 2
  • Inside Contains, KeyType would satisfy those interfaces but it would be like the interfaces were implemented externally, without including the names from those interfaces as unqualified members of KeyType
  • This would only be for function signatures, not interfaces where there are additional considerations.

Implicit constraint option

Advantages:

  • More concise, benefiting readers and writers of the code.
  • Doesn't included redundant information, following the "don't repeat yourself" principle.
  • Callers providing a haystack value of type HashSet(KeyType) already establishes that they have satisfied the constraints.
  • Allows HashSet to evolve its requirements with fewer changes to the code.

Disadvantages:

  • This may introduce additional complications once we allow specializations of HashSet, which might possibly allow HashSet(T) for some T that doesn't satisfy the general requirements.
  • Less explicit.

Opt-in

Another choice would be to have an explicit mark indicating that the requirements should be determined automatically for an indicated generic type parameter.

fn Contains[KeyType:! implicit_requirements]
           (needle: KeyType, haystack: HashSet(KeyType)) -> Bool;
fn Print[KeyType:! Printable & implicit_requirements]
           (set_to_print: HashSet(KeyType));

We might use the keyword auto here, but I worry that is more closely associated with template semantics.

No implicit constraints

Users would be expected to list all requirements.

@josh11b josh11b changed the title Implicit constraints Implicit/inferred generic type constraints Sep 3, 2021
@chandlerc
Copy link
Contributor

Just a clarifying question from my end:

Question: Should the following compile, or should the compiler require that the user explicitly list all of HashSet's requirements for KeyType?

class HashSet(KeyType:! Hashable & HasEquals & Movable);
fn Contains[KeyType:! Type](needle: KeyType, haystack: HashSet(KeyType)) -> Bool;
fn Print[KeyType:! Printable](set_to_print: HashSet(KeyType));
  • Swift supports this: 1, 2
  • Inside Contains, KeyType would satisfy those interfaces but it would be like the interfaces were implemented externally, without including the names from those interfaces as unqualified members of KeyType

Would this implicitly be equivalent to the type-expression constraint syntax from #780 of:

fn Contains[KeyType:! Type](needle: KeyType, haystack: HashSet(KeyType) where KeyType is (Hashable & HasEquals & Movable)) -> Bool;

fn Print[KeyType:! Printable](set_to_print: HashSet(KeyType) where KeyType is (Hashable & HasEquals & Movable));

?

@josh11b
Copy link
Contributor Author

josh11b commented Sep 4, 2021

Yes, they both would add those constraints as if they were external impls.

@chandlerc
Copy link
Contributor

FWIW, thinking about this I'm pretty happy with the idea that constraints on an interface parameter are handled the same as constraints explicitly listed in a where type expression on that interface. It seems clear and easy to explain and provides a pretty significant ergonomic aid and even refactoring aid I suspect.

I'm of course worried by the additional complications if they come up, but I think I'd be willing to cross that bridge when we get there.

@josh11b
Copy link
Contributor Author

josh11b commented Sep 14, 2021

Are we ready to resolve this question? If we are including this feature, what should I call it? Possibilities:

  • implicit constraints
  • implied constraints
  • inferred constraints

@zygoloid
Copy link
Contributor

For terminology, I think I prefer "implied constraints"; it's a bit easier to say than "implicit constraints", and it connects the implication to a specific context (for example, the constraints in the original example are implied by the use of HashSet). "inferred constraints" sounds a bit too much like a description of how rather than what.

But I'd also be happy with "implicit constraints".

@zygoloid
Copy link
Contributor

Decision: Yes, examples such as the original one should compile without requiring the constraints to be duplicated in the function declaration. Our preferred terminology for this is "implied constraints".

@jonmeow jonmeow added the leads question A question for the leads team label Aug 10, 2022
@jonmeow
Copy link
Contributor

jonmeow commented Aug 11, 2022

I think this may not still need a proposal, looks like #818 was probably filling that need.

@chandlerc
Copy link
Contributor

I think this may not still need a proposal, looks like #818 was probably filling that need.

@josh11b to confirm.

@josh11b
Copy link
Contributor Author

josh11b commented Aug 12, 2022

I think this may not still need a proposal, looks like #818 was probably filling that need.

@josh11b to confirm.

Confirmed, #818 addressed this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
leads question A question for the leads team
Projects
None yet
Development

No branches or pull requests

4 participants