Should Fn() -> T implement Into<T>?

The point is with FnOnce() -> T : Into<T> you could have unwrap_or(impl Into<T>), such that you could both write unwrap_or(42) as well as unwrap_or(|| default()). There would need be no distinction between unwrap_or and unwrap_or_else; both would use the same codepath.

However, due to the confusion potential of Fn() -> Self, I do think the split is useful. I can't write the impl for a custom struct Else(impl Fn() -> T), so I don't see how std gets to actually sidestep the underlying issue (rather than just work around it).

(Now, a type-lookup .unwrap_or!($expr), on the other hand... (off-topic do not discuss))

3 Likes

Nothing. I was responding to a question regarding what benefit this change would provide: it cleans up some API surface area. Whether or not it cleans it up enough to be worth the implementation (especially if it's not straightforward) is also worth discussing; it sounds like it's not just "adding an impl". I'm not sure if it's helpful to dismiss the change out of hand.

Clippy even has some helpful lints to point you to the correct unwrap_or_X, and lints against the first example. But assuming most of the difficulties could be ironed out, under the proposed change you could write

op.unwrap_or(42)
op.unwrap_or(default) // ← same number of chars as op.unwrap_or_default()
op.unwrap_or(|| something_more_complicated(x, y, 42))

which might be nice? Not particularly earth shattering, but nice.

2 Likes

I suspect such a change would be difficult for type inference -- e.g. unwrap_or(42) would probably have to fall back to i32, if it's not an outright {integer} inference failure, but of course that won't work for Option<usize>.

4 Likes

Into::into itself can panic, and even if it does there should not be any problem because Into is not an unsafe trait.

Also I think it is clear from the context that they don't talk about panicking there:

Note: This trait must not fail. If the conversion can fail, use TryInto .

1 Like

What do you think "fail" is referring to if not panicking? The conversion must succeed to implement From/Into.

2 Likes

Returning a Result, which is the idiomatic way to do error handling if something fails. Abviously the only interface difference between Into and TryInto is that the conversion method of the latter returns a Result. TryFrom docs says that:

The From trait is intended for perfect conversions, so the TryFrom trait informs the programmer when a type conversion could go bad and lets them decide how to handle it.

The only way TryInto or TryFrom could inform the programmer that something did go bad would be returning Err, so I don't see how "failing" includes panicking in this context.

Then why do this even compile? If Into implementations must not panic, maybe we should mark the Into as an unsafe trait.


panic'ing in an Into::into implementation would merely be a sign of bug, just like how panicking in a checked vector indexing would be. @xfix pointed out that:

And I wanted to point out that IMHO this doesn't really changes anything because Into::into can already panic. You can't assume that Into::into will not panic in an unsafe context, can you?

3 Likes

Since From/Into does not return a Result, there's no other realistic way in which it could "fail", except for panicking.

Yes, Rust doesn't have an effect system, and the type checker allows you to panic as much as you would like. Still, just because From::from() can technically panic, doing so remains to be regarded as unidiomatic, and people won't expect it.

No, because panicking is not inherently unsafe. If it were, we would need to mark literally every function as unsafe.

2 Likes

I didn't mean that. If not panicking would literally be a requirement for implementing Into, Into should have been an unsafe trait.

4 Likes

logically, Into::into should not panic. Unsafe Code cannot rely on this for soundness, but safe code could rely on this for behaving properly.

4 Likes

Note that there's impl<T: Ord> From<Vec<T, Global>> for BinaryHeap<T> in std, so you probably need to add the same requirement to never panic to Ord and/or PartialOrd (which probably means "no math allowed here because it could overflow"). And also Clone and ToOwned for a number of cloning implementations. And the program, obviously, can still have an allocation failure, which will probably become a potential panic under RFC 2116.

6 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.