Why should we prefer `std::convert::From` vs `std::convert::Into`?


#1

Hi, on the std::convert::Into trait page, it says:

Library authors should not directly implement this trait, but should prefer implementing the From trait, which offers greater flexibility and provides an equivalent Into implementation for free

The “greater flexibility” statement is hand-wavy to me (i.e. “believe me! it’s true” instead of “this is the rationale”).

In one of my projects, I’ve got:

  • a StandardRecord struct
  • a varying number of custom record structs, e.g. Custom1Record, Custom2Record

Since the custom record structs can keep growing, it seems to make sense that every time I add another CustomXRecord struct, I should also impl Into<StandardRecord> for CustomXRecord. But the advice above turns it around and says, actually you should impl From<CustomXRecord> for StandardRecord.

So there’s two questions here:

  • What’s the magic behind prefer From over Into?
  • Should I put the impl From<CustomXRecord> for StandardRecord inside the CustomXRecord module? The CustomXRecord and StandardRecords currently all live in the same crate.

#2

It’s the latter part of that statement that gives the flexibility. Specifically, there’s a blanket impl:

impl<T, U> Into<U> for T 
where U: From<T>

So if you implement From, you get Into for free, just like it says.


#3

Ah, I think I misinterpreted the Generic impls section (which happens to be the same text on both From and Into pages):

From<T> for U implies Into<U> for T

I guess that means that if you implement Into<U> for T, you don’t get From<T> for U for free.

Any pointers for the second question?


#4

No, put it into the module containing StandardRecords, since constructing a StandardRecord probably involves invoking the private constructor or messing with internal state. Well, it probably doesn’t, which is why the choice seems arbitrary here, but if it did, you’d certainly be forced to.


#5

I’d put it into the StandardRecord module. The fn from(x: CustomRecordX) -> StandardRecord is basically a constructor of StandardRecord, and those belong there.


#6

I feel like From basically being a constructor (as @vitalyd pointed out is) a great reason to prefer From over Into.

It also gives me an “orphan” like feeling implementing Into<..> which is a trait my crate doesn’t own for a type I don’t own either. I did have a look at orphan rules in rust and found a closed issue which states:

… Specifically that input parameters cannot be used as proof of coherence, i.e. impl ExternTrait<LocalType> for ExternType, is no longer allowed.

So to me it looks like implementing Into instead of From didn’t even work for a while. I’m not sure if it does now.