Skip to content

Commit 13a9c18

Browse files
Add discussion of "unioning" traits
1 parent 5d1080a commit 13a9c18

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

text/3437-implementable-trait-alias.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ so this change would break every `impl Iterator` block in existence.
157157

158158
## Speculative example: `Async` trait
159159

160-
There has been some discussion about a variant of the `Future` trait with an `unsafe` poll method, to support structured concurrency ([here](https://rust-lang.github.io/wg-async/vision/roadmap/scopes/capability/variant_async_trait.html) for example). *If* such a change ever happens, then the same "weak"/"strong" relationship will arise: the safe-to-poll `Future` trait would be a "strong" version of the unsafe-to-poll `Async`. As the linked design notes explain, there are major problems with expressing this relationship in today's Rust.
160+
There has been some discussion about a variant of the `Future` trait with an `unsafe` poll method, to support structured concurrency ([here](https://rust-lang.github.io/wg-async/vision/roadmap/scopes/capability/variant_async_trait.html) for example). *If* such a change ever happens, then the same "weak"/"strong" relationship will arise: the safe-to-poll `Future` trait would be a "strong" version of the unsafe-to-poll `Async`. As the linked design notes explain, there are major problems with expressing that relationship in today's Rust.
161161

162162
# Guide-level explanation
163163

@@ -323,6 +323,47 @@ More experience with those features might unearth better alternatives.
323323
(For example, `trait Foo = Bar + Send;` could be made implementable). However, this would arguably make implementability rules less intuitive, as the symmetry with `impl` blocks would be broken.
324324
- Another possibility is to require an attribute on implmenentable aliase; e.g. `#[implementable] trait Foo = ...`. This would make the otherwise-subtle implementability rules explicit, but at the cost of cluttering the attribute namespace and adding more complexity to the language.
325325

326+
## What about combining multiple prtimary traits, and their items, into one impl block?
327+
328+
It's possible to imagine an extension of this proposal, that allows trait aliases to be implementable even if they have multiple primary traits. For example:
329+
330+
```rust
331+
trait Foo = Clone + PartialEq;
332+
333+
struct Stu;
334+
335+
impl Foo for Stu {
336+
fn clone(&self) -> Self {
337+
Stu
338+
}
339+
340+
fn eq(&self, other: &Self) -> bool {
341+
true
342+
}
343+
}
344+
```
345+
346+
Such a feature could be useful when a trait has multiple items and you want to split it in two.
347+
348+
However, there are some issues. Most glaring is the risk of name collisions:
349+
350+
```rust
351+
trait A {
352+
fn foo();
353+
}
354+
355+
trait B {
356+
fn foo();
357+
}
358+
359+
// How would you write an `impl` block for this?
360+
trait C = A + B;
361+
```
362+
363+
Such a feature could also make it harder to find the declaration of a trait item from its implementation, especially if IDE "go to definition" is not available. One would need to first find the trait alias definition, and then look through every primary trait to find the item. (However, given the current situation with postfix method call syntax, maybe this is an acceptable tradeoff.)
364+
365+
Perhaps a more narrowly tailored version of this extension, in which both subtrait and supertrait explicitly opt-in to support sharing an `impl` block with one another, would satisfy the backward-compatibility use-case while avoiding the above issues. I think exploring that is best left to a future RFC.
366+
326367
# Prior art
327368

328369
- [`trait_transformer` macro](https://github.com/google/impl_trait_utils)

0 commit comments

Comments
 (0)