mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 10:41:03 +01:00
134 lines
6.1 KiB
Markdown
134 lines
6.1 KiB
Markdown
# Implicit conversions for aggregates
|
|
|
|
<!--
|
|
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
Exceptions. See /LICENSE for license information.
|
|
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
-->
|
|
|
|
[Pull request](https://github.com/carbon-language/carbon-lang/pull/981)
|
|
|
|
<!-- toc -->
|
|
|
|
## Table of contents
|
|
|
|
- [Problem](#problem)
|
|
- [Background](#background)
|
|
- [Proposal](#proposal)
|
|
- [Details](#details)
|
|
- [Rationale based on Carbon's goals](#rationale-based-on-carbons-goals)
|
|
- [Alternatives considered](#alternatives-considered)
|
|
- [Field order is not significant](#field-order-is-not-significant)
|
|
- [Different field orders are incompatible](#different-field-orders-are-incompatible)
|
|
- [Explicit instead of implicit conversions](#explicit-instead-of-implicit-conversions)
|
|
|
|
<!-- tocstop -->
|
|
|
|
## Problem
|
|
|
|
What operations are supported by default between two data classes with the same
|
|
fields in different orders? What implicit conversions are allowed between
|
|
aggregates, such as arrays, tuples, and data classes?
|
|
|
|
## Background
|
|
|
|
- Comparison operators more generally were added to Carbon in
|
|
[proposal #702: Comparison operators](https://github.com/carbon-language/carbon-lang/pull/702)
|
|
- An initial take on these questions was originally in proposal
|
|
[proposal #561: Basic classes: use cases, struct literals, struct types, and future work](https://github.com/carbon-language/carbon-lang/pull/561)
|
|
but postponed until we had agreement on the right approach.
|
|
- The discussion that eventually reached an agreement took place in
|
|
[question-for-leads issue #710: Default comparison for data classes](https://github.com/carbon-language/carbon-lang/issues/710)
|
|
|
|
## Proposal
|
|
|
|
We propose that we should permissively allow operations between data classes and
|
|
other aggregates with different field orders and types where we can. Field order
|
|
in data classes is salient, but mostly determines the order that operations are
|
|
performed. The only case where different field orders will forbid an operation
|
|
is with ordering comparisons, where the field order determines the answer
|
|
returned, not just the order of execution.
|
|
|
|
## Details
|
|
|
|
Changes have been made to:
|
|
|
|
- [docs/design/classes.md](/docs/design/classes.md),
|
|
- [docs/design/tuples.md](/docs/design/tuples.md).
|
|
|
|
These changes are intended to apply to all aggregate types, including arrays.
|
|
|
|
## Rationale based on Carbon's goals
|
|
|
|
This proposal advances Carbon's goals:
|
|
|
|
- [Software and language evolution](/docs/project/goals.md#software-and-language-evolution):
|
|
This proposal allows changes to field order and type to be made
|
|
incrementally.
|
|
- [Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write):
|
|
This proposal provides useful and expected facilities for data classes and
|
|
other aggregate types by default.
|
|
|
|
## Alternatives considered
|
|
|
|
Alternatives were considered in:
|
|
|
|
- [question-for-leads issue #710: Default comparison for data classes](https://github.com/carbon-language/carbon-lang/issues/710)
|
|
- [open discussion on 2021-11-29](https://docs.google.com/document/d/1YhwNKLxQsWf8NPVaRm9PvgPmSM3PIK_KlD1gpNuUfwY/edit#heading=h.6komy889g3hc)
|
|
|
|
### Field order is not significant
|
|
|
|
We considered not making field order significant in struct types, making them
|
|
into unordered collections of named fields. This view is consistent with order
|
|
not being significant in initializers in prior class proposal
|
|
[#561](https://github.com/carbon-language/carbon-lang/pull/561). This had a
|
|
number of consequences:
|
|
|
|
- Users would not have control over the order of operations performed
|
|
field-by-field, such as comparisons, unless they use a nominal class type
|
|
and implement those operations explicitly.
|
|
- Order comparison operators, like `<` and `<=`, would not be supported. We
|
|
considered defining an unspecified-but-fixed ordering, for use in things
|
|
like binary search, accessed in some other way than the ordinary comparison
|
|
operators.
|
|
|
|
Ultimately, we decided that field order was a salient property of struct types,
|
|
at least determining the layout of the data in memory, and we should use it to
|
|
determine the order of operations and how to compare lexicographically.
|
|
|
|
**Reference:** See
|
|
[this comment by `geoffromer` on #710](https://github.com/carbon-language/carbon-lang/issues/710#issuecomment-893866801).
|
|
|
|
### Different field orders are incompatible
|
|
|
|
Rather than picking the left-hand argument's field order when the orders were
|
|
different, we considered requiring the field order to match when performing all
|
|
comparisons, including equality comparisons. An explicit conversion to a common
|
|
type would be required to perform a comparison when the field orders did not
|
|
match.
|
|
|
|
The current proposal is more convenient for users, and has the property that
|
|
executing `a = b` results in the condition `a == b` being true, even when `a`
|
|
and `b` have different field orders. We also believed that operations like
|
|
assignment between structs with different field orders would be more efficiently
|
|
implemented using field-by-field assignment rather than a conversion to the
|
|
left-hand type followed by assignment, and so it was natural to support the
|
|
former directly.
|
|
|
|
### Explicit instead of implicit conversions
|
|
|
|
We expected a lot of code trying to pass values between functions using
|
|
different field orders would use destructuring instead of direct conversion. As
|
|
a result, we thought it might be safer to require explicit conversions to avoid
|
|
silently converting, say, 10,000 `i8` values to `i64`.
|
|
|
|
However, there were some important use cases for performing the conversion
|
|
implicitly, such as `(1, 1)` converting to an `(i8, i8)` value. We did not want
|
|
rules that distinguish this case from other implicit conversions, for
|
|
simplicity. Similarly, we wanted the set of conversions to be consistent across
|
|
aggregate types, including tuples, arrays, and data classes. We can amend these
|
|
rules in the future to address cases that are surprising to users in practice.
|
|
|
|
**Reference:** See
|
|
[this comment by `chandlerc` on #710](https://github.com/carbon-language/carbon-lang/issues/710#issuecomment-983579560).
|