Allowing interfaces to define default values for its associated entities. This:
- Helps with evolution by reducing the changes needed to add new members to an interface.
- Reduces boilerplate when some value is more common than others.
- Addresses the gap between the minimum necessary for a type to provide the desired functionality of an interface and the breadth of API that user's desire.
As an alternative, final values can be provided instead, which can't be overridden, but are more predictable for users and may avoid dynamic dispatch overhead in some cases.
Example:
```
// Interface parameter has a default of `Self`
interface Add(Right:! Type = Self) {
// `AddWith` *always* equals `Right`
final let AddWith:! Type = Right;
// `Result` has a default of `Self`
let Result:! Type = Self;
fn DoAdd[me: Self](right: Right) -> Result;
}
impl String as Add() {
// Right == AddWith == Result == Self == String
fn DoAdd[me: Self](right: Self) -> Self;
}
```
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
There were some concerns about facet types leaking out of generic code in return types. Some initial fixes for this were done in [PR #900](https://github.com/carbon-language/carbon-lang/pull/900), but there remain concerns, for example when associated types are involved.
In particular, given an interface method with return type using an associated type, as in:
```
interface Deref {
let Result:! Type;
fn DoDeref[me: Self]() -> Result;
}
class IntHandle {
impl as Deref {
let Result:! Type = i32;
fn DoDeref[me: Self]() -> Result { ... }
}
}
```
Since `Result` has type `Type`, we had the problem that `IntHandle.DoDeref` would have to return `i32 as Type`, instead of the desired `i32`.
We also think we can simplify the model by eliminating the facet type concept and syntax.
This proposal removes facet types, introduces archetypes in their place, clarifies how associated types work outside of a generic function, and specifies how a generic `let` statement in a function body works.
Co-authored-by: Wolff Dobson <wolffg@users.noreply.github.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Define initialization, assignment, comparison, and implicit conversion between data classes with different field orders and/or types.
Implements the decision made in #710 .
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Add support for marking impls as `final` to say they can't be specialized. This allows generic functions that see that the impl applies to determine the values for its associated types. For example this allows us to say that the implementation of the `Deref` interface for pointers can't be specialized. Otherwise, `*p` could have unknown type in a generic function.
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
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>
Add an appendix with the rationale for and alternatives to coherence, along with an entry in the terminology and updates to the coherence discussion in the goals.
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Implementations of interfaces are as public as the names used in their signature. No access control modifiers are allowed on `impl` declarations.
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Includes a variety of changes:
Int -> i32
this -> me
expand terminology doc and add links to it
fix text to reflect inline external impl introduced in Support external impl in class and adapter scopes. #905
no longer have plans for runtime type parameters
style updates like removing parentheticals and "we"
observe is a "declaration" not a "statement", since it can appear outside function bodies
many individual updates, clean-ups, and fixes
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This proposal describes `where` clauses that can add constraints on a type-of-type, for example define restrictions on its associated types. Example:
```
fn FindFirstPrime[T:! Container where .Element = i32]
(c: T) -> Optional(i32) {
// The elements of `c` have type `T.Element`, which is `i32`.
...
}
fn PrintContainer[T:! Container where .Element is Printable](c: T) {
// The type of the elements of `c` is not known, but we do know
// that type satisfies the `Printable` interface.
...
}
```
Some other constraints, such as `Sized` are defined as type-of-types directly, possibly parameterized.
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This proposal provides an `as` expression for casting. This supports implicit conversions plus some safe and unsurprising conversions that we do not support implicitly:
* lossy but fully defined conversions to floating-point types
* conversion from `bool` to integer types
* conversion between adaptors and their adapted type, and more generally between compatible types
This facility can be extended by implementing the `As(TargetType)` interface for a type.
Co-authored-by: Geoff Romer <gromer@google.com>
Co-authored-by: josh11b <josh11b@users.noreply.github.com>
This list was extracted from currently-approved proposals and
corresponding design documents. This is intended to be a summary of the
status quo, not a change.
Proposal to support a limited set of implicit conversions.
This would generally permit only implicit conversions that are lossless and semantics-preserving. In particular, this proposal allows:
- Conversion from an integer type to a wider integer type of the same signedness, and from an unsigned integer type to a wider signed integer type.
- Conversion from an integer type to a floating-point type that has enough mantissa bits to exactly represent all integers in the source type.
- Conversion from integer literals to integer and floating-point types that can represent them.
- Conversion from floating-point literals to floating-point types that can represent them.
- Conversions required for generics: conversions of values between facet types, and conversions of types between type-of-types, as described in the generics proposals.
- Conversions required for inheritance: derived-to-base conversions for class pointers and class values.
Other conversions, such as lossy conversions between arithmetic types and conversions between bool and other types are not supported.
Co-authored-by: josh11b <josh11b@users.noreply.github.com>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Co-authored-by: Geoff Romer <gromer@google.com>
These aren't really statements (because they're not executed at run time), and it's debatable whether they're declarations, since their primary purpose isn't to introduce a name. On Discord, "directive" seemed to be the consensus choice for an alternate term.
This is based on discussion on #732: that we should probably parse the invalid whitespace, then reject it as part of string validation, rather than having different parses. I worry the question of "how is this parsed" may lead to subtly unexpected results if we aren't consistent, so I'm switching the logic from the lexer to the unescape library (and also adjusting the list of rejected whitespace).
I've modified the text from the proposal slightly, focusing the overview more on a design setup, but mostly kept the details. One important thing here is I noticed that raw tab characters are disallowed -- this was a little buried before, and I've now updated the list of characters allowed in a string to exclude tabs. Additionally, I've noted `\0D` in the list of escapes as explicitly invalid.
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Add support for nominal (or "named") classes with encapsulation. Inheritance will be in a later proposal. Here is an example of the proposed syntax:
```
class Circle {
fn Create(c: Point, r: f32) -> Self {
return {.center = c, .radius = r};
}
fn Diameter[me: Self]() -> f32 {
return me.radius * 2;
}
fn Expand[addr me: Self*](distance: f32);
private var center: Point;
private var radius: f32;
}
fn Circle.Expand[addr me: Self*](distance: f32) {
me->radius += distance;
}
```
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Moving "Global variables" out of "Alternatives"; I don't think it's really been considered in the same way that others have, so there's no reference to provide.
This proposal defines the very basics of `class` types, primarily focused on:
- use cases including: data classes, encapsulated types, inheritance with and without `virtual`, interfaces as base classes, and mixins for code reuse;
- anonymous data types for called _structural data classes_ or _struct types_. Struct literals are used to initialize class values and ad-hoc parameter and return types with named components; and
- future work, including the provisional syntax already in use for features that have not been decided.
The intent is to both make some small incremental progress and get agreement on direction. As such it doesn't include things like nominal types, methods, access control, inheritance, etc.
It proposes this struct type and literal syntax:
```
var p: {.x: Int, .y: Int} = {.x = 0, .y = 1};
```
Note that it uses commas (`,`) between fields instead of semicolons (`;`), and no introducer for types or literal values.
Incorporates decisions from #665 , #653 , #651
Co-authored-by: Geoff Romer <gromer@google.com>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This implements decision #565 to use `T:! Type` to declare generic parameters, and `template T:! Type` for template parameters.
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Expand the description of the structure of a proposal PR. Clarify that
the full PR is the proposal, not only the P-numbered document. Start a
design style guide and use it to describe which parts of a proposal
should not end up in the design.
Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com>
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>