You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: text/3634-scoped-impl-trait-for-type.md
+36-12Lines changed: 36 additions & 12 deletions
Original file line number
Diff line number
Diff line change
@@ -232,23 +232,40 @@ The page for [`TypeId`] gains two sections with the following information:
232
232
```markdown
233
233
# `TypeId` and scoped implementations
234
234
235
-
To make sure that that are no mix-ups between, for example, `HashSet<T>` and `HashSet<T as Hash in module>`, any such difference implies distinct `TypeId`s between such discretised generics (and that the types are not mutually assignable).
235
+
To make sure that that are no mix-ups between, for example, `HashSet<T>` and
236
+
`HashSet<T as Hash in module>`, any such difference implies distinct `TypeId`s between
237
+
such discretised generics (and that the types are not mutually assignable).
236
238
237
-
This also affects trait-bounded generic type parameters: If `T` is bounded on `Hash`, then `TypeId::of::<T>()` results in distinct `TypeId`s in that context depending on the captured implementation.
239
+
This also affects trait-bounded generic type parameters: If `T` is bounded on `Hash`, then
240
+
`TypeId::of::<T>()` results in distinct `TypeId`s in that context depending on the
241
+
captured implementation.
238
242
239
-
However, note that `TypeId::of::<T>()` and `TypeId::of::<T as Hash in module>()` are always equivalent for one definition of `T`, as `TypeId::of`'s implementation does **not** have a `T: Hash` bound!
243
+
However, note that `TypeId::of::<T>()` and `TypeId::of::<T as Hash in module>()` are
244
+
always equivalent for one definition of `T`, as `TypeId::of`'s implementation does **not**
245
+
have a `T: Hash` bound!
240
246
241
-
For convenience (so that their values are easily interchangeable across crates), the following types ignore scoped implementations *on* their generic arguments in terms of *their own* type identity: […]
247
+
For convenience (so that their values are easily interchangeable across crates), the
248
+
following types ignore scoped implementations *on* their generic arguments in terms of
249
+
*their own* type identity: […]
242
250
243
-
Despite this, differences in *type arguments'* discrete identities (for example from scoped implementations captured *in* them) distinguish the type identity of *all* discretised generics they appear in.
251
+
Despite this, differences in *type arguments'* discrete identities (for example from
252
+
scoped implementations captured *in* them) distinguish the type identity of *all*
253
+
discretised generics they appear in.
244
254
245
255
# `TypeId::of::<Self>()` may change for values of generics
246
256
247
-
To make type-erased collections sound and unsurprising by default, it's sound to transmute between instances of an external generic type that differ only in their captured scoped implementations, **iff and only iff** no inconsistency is ever observed by bounds (including across separate function calls).
257
+
To make type-erased collections sound and unsurprising by default, it's sound to transmute
258
+
between instances of an external generic type that differ only in their captured scoped
259
+
implementations, **iff and only iff** no inconsistency is ever observed by bounds
260
+
(including across separate function calls).
248
261
249
-
However, this poses a problem: `TypeId::of::<Self>()` (just like the written-out form of any type that doesn't ignore scoped implementations) takes *all* differences in captured implementation environments into account, not just those relevant to trait bounds.
262
+
However, this poses a problem: `TypeId::of::<Self>()` (just like the written-out form of
263
+
any type that doesn't ignore scoped implementations) takes *all* differences in captured
264
+
implementation environments into account, not just those relevant to trait bounds.
250
265
251
-
As such, prefer `TypeId::of::<T>()` whenever possible in order to make only the distinctions you require. You can use tuples to combine multiple type parameters without over-distinguishing: `TypeId::of::<(S, T)>()`
266
+
As such, prefer `TypeId::of::<T>()` whenever possible in order to make only the
267
+
distinctions you require. You can use tuples to combine multiple type parameters without
268
+
over-distinguishing: `TypeId::of::<(S, T)>()`
252
269
```
253
270
254
271
> These rules and the reasons for them are explained in detail in the [reference-level-explanation] below, as well as in [logical-consistency] as part of [rationale-and-alternatives]. It may be a good idea to link to similar longer explanations from the standard library docs above, even if just as "See also:"-style references for further reading.
@@ -266,7 +283,8 @@ The pages for [implementation-invariant-generics] gain a section similar to the
266
283
```markdown
267
284
# Implementation-invariant generic
268
285
269
-
This type does not by itself capture scoped implementation environments when discretised. See [`TypeId` and scoped implementations] for more information.
286
+
This type does not by itself capture scoped implementation environments when discretised.
287
+
See [`TypeId` and scoped implementations] for more information.
270
288
```
271
289
272
290
where ``[`TypeId` and scoped implementations]`` is a link to the section added to the `TypeId` page above.
@@ -278,7 +296,10 @@ The page for [`transmute`] gains a section with the following information:
278
296
```markdown
279
297
# `transmute` and scoped implementations
280
298
281
-
It is sound to transmute between discretised generic types that differ only in their captured scoped implementation environments, **but only iff** such differences are **never** observed by bounds on their implementation, including functions that imply such by being implemented for discrete instances of the generic.
299
+
It is sound to transmute between discretised generic types that differ only in their
300
+
captured scoped implementation environments, **but only iff** such differences are
301
+
**never** observed by bounds on their implementation, including functions that imply such
302
+
by being implemented for discrete instances of the generic.
282
303
```
283
304
284
305
> As far as I can tell, this is only practically relevant for certain kinds of type-erasing collections, like type-erasing hash maps and B-trees, of which I couldn't find any examples on crates.io.
@@ -292,9 +313,12 @@ It is sound to transmute between discretised generic types that differ only in t
292
313
The page on [Transmutes] gains the following warning in addition to the existing ones:
293
314
294
315
```markdown
295
-
- It is unsound to change [captured scoped implementations] via transmute for any external type if this change ever causes a contradiction observable by the transmuted value's implementation.
316
+
- It is unsound to change [captured scoped implementations] via transmute for any external
317
+
type if this change ever causes a contradiction observable by the transmuted value's
318
+
implementation.
296
319
297
-
This can happen due to bounds on called functions and/or because a called function is implemented for a specific type discretised from the generic.
320
+
This can happen due to bounds on called functions and/or because a called function is
321
+
implemented for a specific type discretised from the generic.
298
322
```
299
323
300
324
`[captured scoped implementations]` should link to documentation introducing scoped `impl Trait for Type`.
0 commit comments