Skip to content

Commit

Permalink
Elaborate on details about trans, designd ecisions, and OIBIT behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
Kimundi committed Feb 2, 2016
1 parent 3f8fec6 commit 34cb520
Showing 1 changed file with 64 additions and 19 deletions.
83 changes: 64 additions & 19 deletions text/0000-conservative-impl-trait.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,21 @@ lifted at some point in the future.
closure traits, function pointers, or any non-return type position.
- The function body can return values of any type that implements Trait,
but all return values need to be of the same type.
- Outside of the function body, the return type is only known to implement Trait.
- As an exception to the above, OIBITS like `Send` and `Sync` leak through an
abstract return type. This will cause some additional complexity in the
compiler due to some non-local typechecking becoming neccessary.
- The return type is unnameable.
- As far as the typesystem and the compiler is concerned,
the return type outside of the function would
not be a entirely "new" type, nor would it be
a simple type alias. Rather, its semantic would be very similar to that of
_generic type paramters_ inside a function, with small differences caused
by being an _output_ rather than an _input_ of the function.
- The type would be known to implement the specified traits.
- The type would not be known to implement any other trait, with
the exception of OIBITS and default traits like `Sized`.
- The type would not be considered equal to the actual underlying type.
- The type would not be allowed to be implemented on.
- The type would be unnameable, just like closures and function items.
- Because OIBITS like `Send` and `Sync` will leak through an
abstract return type, there will be some additional complexity in the
compiler due to some non-local type checking becoming necessary.
- The return type has a identity based on all generic parameters the
function body is parametrized by, and by the location of the function
in the module system. This means type equality behaves like this:
Expand Down Expand Up @@ -126,17 +136,35 @@ lifted at some point in the future.
}
```

- Abstract return types are considered `Sized`, just like all return types today.

#### Limitation to only return type position

There have been various proposed additional places where abstract types
might be usable. For example, `fn x(y: @Trait)` as shorthand for
`fn x<T: Trait>(y: T)`.
Since the exact semantic and user experience for these
locations are yet unclear
(`@Trait` would effectively behave completely different before and after the `->`),
this has also been excluded from this proposal.
- The code generation passes of the compiler would
not draw a distinction between the abstract return type and the underlying type,
just like they don't for generic paramters. This means:
- The same trait code would be instantiated, for example, `-> @Any`
would return the type id of the underlying type.
- Specialization would specialize based on the underlying type.

#### Why this semantic for the return type?

There has been a lot of discussion about what the semantic of
the return type should be, with the theoretical extremes being "full return type inference" and "fully abstract type that behaves like a autogenerated newtype wrapper"

The design as choosen in this RFC lies somewhat in between those two,
for the following reasons:

- Usage of this feature should not imply worse performance
than not using it, so specialization and codegeneration has to
treat it the same.
- Likewise, there should not be any bad interactions
caused by part of the typesystem treating the return type different
than other parts, so it should not have its own "identity"
in the sense of allowing additional or different trait or inherent implementations.
- It should not enable return type inference in item signatures,
so the exact underlying type needs to be hidden.
- It should not cause type errors to change the function
body and/or the underlying type as long as the specifed trait
bounds are still satisfied.
- As a exception to the above, it should not act as a barrier to OIBITs like
`Send` and `Sync` due to ergonomic reasons. For more details, see next section.

#### OIBIT semantic

Expand All @@ -145,9 +173,11 @@ it effectively opens a channel where the result of function-local type inference
item-level API, but has been deemed worth it for the following reasons:

- Ergonomics: Trait objects already have the issue of explicitly needing to
declare `Send`/`Sync`-ability, and not extending this problem to abstract return types
is desireable.
- Low real change, since the situation already exists with structs with private fields:
declare `Send`/`Sync`-ability, and not extending this problem to abstract
return types is desireable. In practice, most uses
of this feature would have to add explicit bounds for OIBITS
if they want to be maximally usable.
- Low real change, since the situation already somewhat exists on structs with private fields:
- In both cases, a change to the private implementation might change whether a OIBIT is
implemented or not.
- In both cases, the existence of OIBIT impls is not visible without doc tools
Expand All @@ -158,6 +188,10 @@ This means, however, that it has to be considered a silent breaking change
to change a function with a abstract return type
in a way that removes OIBIT impls, which might be a problem.

But since the number of used OIBITs is relatvly small,
deducing the return type in a function body and reasoning
about whether such a breakage will occur has been deemed as a manageable amount of work.

#### Anonymity

A abstract return type can not be named - this is similar to how closures
Expand All @@ -174,6 +208,17 @@ abstract return types could get upgraded to having a name transparently.
Likewise, if `typeof` makes it into the language, then you could refer to the
return type of a function without naming it.

#### Limitation to only return type position

There have been various proposed additional places where abstract types
might be usable. For example, `fn x(y: @Trait)` as shorthand for
`fn x<T: Trait>(y: T)`.

Since the exact semantic and user experience for these
locations are yet unclear
(`@Trait` would effectively behave completely different before and after the `->`),
this has also been excluded from this proposal.

#### Type transparency in recursive functions

Functions with abstract return types can not see through their own return type,
Expand Down

0 comments on commit 34cb520

Please sign in to comment.