Pre-Pre-RFC: Partially Transitive `From` via removing `From<X> for X`

Then, there is no From<A> for C . This is a libs post anyway.

In that case I don't see how your proposal even makes From transitive in the first place!

1 Like

I suggest read the initial post again, and do the following exercises:

  • Draw the call stack of A::<B<usize>>::from(0usize) where B::from(0usize) is called.
  • Is A::<B<A<usize>>>::from also automatically implemented in this case? Why?
  • How will impl From<X> for X cause conflicted implementation?

Wait, so, are you proposing that library authors should write an impl like your "toy examples" from your initial post, for every From-conversion they want to implement?

Then, let me revise my objection:

If any collection of libraries contains manual implementations of A -> B and A -> C, and I have a downstream crate with a type D which I want to be convertible from both B and C, I cannot now do this, because they would conflict. That would be super annoying! It would mean that "B and C both being convertible-from A" precludes "B and C both being convertible-to any type D", and vice versa. And, as I mentioned, it would make any new impl a breaking change (if the library previously implemented only A -> B, then I would be permitted to implement both B -> D and C -> D, but if the library later added an impl of A -> C, then my code would break).

2 Likes

You can implement From<B> for D and From<C> for D separately. I only suggest removing From<X> for X to make some of the transitive impl From possible. I believe there are some issues to be addressed, but it shouldn't involve conflicted implementations. Based on your confusion before, I modified the title to Partially Transitive.

Okay, "partially transitive" makes it much less confusing.

Also, I just wrote some example code, and I see that I missed something in the last post: if you write one of these "transitive impls" to convert anything to D, you actually cannot write any other impls that convert anything to D. So it would only work for types that are willing to permanently commit that there's only one other type that could possibly convert to them. Including being unable to convert the type to itself, for that matter.

I'm happy that you finally get it. :innocent:

That sounds like a very different "kind" of conversion than what From is usually used for.

Do you have an example of a situation where a library would want this? That is, an example of a type C which wants to be implicitly convertible from any type A where one downstream crate knows how to convert B to C and another crate knows how to convert A to B, where also neither of the types B or C would ever care to be converted from anything else in the same way? (With anything less complicated than this, the existing From can handle it just fine.)

That can be rather sophisticated. Let me explain how I came up with this.

I was implementing a parser library. Sometimes, a non-terminal symbol may be converted to another without changing its inner, and it only parses from one rule. For example, Span<T> attach a span to T, where T implements a parsing function like T::parse . This also applicable Box<T> and other stuff.

What I want to do is when From<T> Span<T> is implemented, Span::<T>::parse is implemented. But what about Box<Span<T>>? If From<T> for T always presents, this will cause conflicted implementation.

I'm not sure I understand. Are you saying that you want to automatically have a Box<Span<T>>::parse, meaning that it must be a trait method and you'd need an impl like impl<T: Parse, U: From<T>> Parse for U?

That doesn't sound like the same thing, so perhaps I've misunderstood. Code examples would help.

1 Like

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