Skip to content

Commit 3296f89

Browse files
committed
Add appendix on using newtypes/type tags
Signed-off-by: Nick Cameron <[email protected]>
1 parent f8626e1 commit 3296f89

File tree

1 file changed

+28
-1
lines changed

1 file changed

+28
-1
lines changed

text/0000-dyno.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ fn report_error(e: &dyn Error) {
6161
}
6262

6363
// Help text suggestion.
64-
// Note, we should use a newtype here to prevent confusing different string context information.
64+
// Note, we should use explicit tags or a newtype here to prevent confusing different string
65+
// context information (see appendix).
6566
if let Some(suggestion) = e.get_context_ref::<str>() {
6667
emit_suggestion(suggestion);
6768
}
@@ -288,7 +289,33 @@ Extending the API of `Error` is a primary motivation for this RFC, but those ext
288289

289290
It was suggested by @Plecra in the [comments](https://github.com/rust-lang/rfcs/pull/2895#issuecomment-735713486) of RFC 2895, that this mechanism could be used for providing data from a future's `Context` object. That is a more demanding application since it is likely to require `&mut` references, objects with complex lifetimes, and possibly even closures to be returned. That has motivated seeking a general API for `provide_any`, rather than only supporting `'static` lifetimes.
290291

292+
Recommendations for how to use the API, in particular when to provide or request a value using a plain type, type tag, or special purpose newtype. See the appendix for discussion and examples.
293+
291294
# Future possibilities
292295
[future-possibilities]: #future-possibilities
293296

294297
A possible extension to this work is full downcasting using type tags - a proper alternative to `Any`. Such downcasting is available in dyno and is an implementation detail of the proof of concept implementation for this RFC. It is not part of `provide_any`'s interface in order to minimise the proposal and avoid overlap with `Any`, however, I don't see any technical issues with exposing such functionality in the future if there is demand.
298+
299+
# Appendix: using tags or newtypes
300+
301+
One issue with using type-based provision is that an object might reasonably provide many different values with the same type. If the object intends to provide multiple values with the same type, then it must distinguish them. Even if it doesn't, the user might request a value expecting one thing and get another with the same type, leading to logic errors (e.g., requesting a string from `MyError` expecting an error code and getting a suggestion message).
302+
303+
There are two possible solutions (both of these use the API as proposed, neither requires extensions): wrap values in value-specific newtypes, or use value-specific type tags.
304+
305+
I'll explain these options in the context of the `MyError` example.
306+
307+
Using newtypes, the `MyError` author would provide a `Suggestion` newtype: `pub struct Suggestion(pub String)`. A user would use `get_context::<Suggestion>()` (or otherwise specify the type, e.g., `let s: Suggestion = e.get_context().unwrap();`) and would receive a `Suggestion` which they would then have to unpack to retrieve the string value. This approach only works for owned `String`s: newtypes cannot wrap unsized values, and keeping a reference in the newtype would require using an explicit tag, making the newtype option strictly worse than the type tag option.
308+
309+
Using type tags, the `MyError` author would provide a `SuggestionTag` type tag:
310+
311+
```rust
312+
pub struct SuggestionTag;
313+
314+
impl<'a> TypeTag<'a> for SuggestionTag {
315+
type Type = &'a str;
316+
}
317+
```
318+
319+
The user would use `get_context_by_type_tag::<SuggestionTag>` to retrieve the suggestion. This approach supports references, so the suggestion message does not need to be cloned, and returns the string directly to the user without them having to unpack a newtype. However, it does require the user to understand the type tag concept.
320+
321+
Note that the type tags option relies on their being a potential many-to-one relationship between type tags and types.

0 commit comments

Comments
 (0)