I’m not convinced that the problem is actually a problem. Suppose someone writes a type PairOfNumbers with a couple fields. The author did not define a serialization. You use it in another type and want it to serialize it as:
{ "a": 1, "b": 2 }
I use it and want to serialize it as:
[ 1, 2 ]
What we’re doing is fine. You should get your serialization and I should get mine. But if either of us declares, process-wide, that one of us has determined the One True Serialization of PairOfInts, I think we are wrong.
Sure, maybe current Rust and current serde make it awkward to declare non-global serializers, but that doesn’t mean that coherence is a mistake.
> What we’re doing is fine. You should get your serialization and I should get mine. But if either of us declares, process-wide, that one of us has determined the One True Serialization of PairOfInts, I think we are wrong.
Well, fine, but then you need to actually implement a module system or something. Currently trait impls are program-wide, and if you say that you're not allowed to make global impls of a trait then that's the same as saying you're not allowed to implement traits at all.
Rust’s orphan rule has the property that there is no spooky action at all distance in terms of program semantics. If I write a library, my library behaves the same way regardless of whether the main program imports a different library.
In any case, the OP’s proposed “incoherent” scheme actually is a module system of sorts for conflicting trait impls, and it seems about right for something like serialization.
Perhaps that's fine in the particular case of serialization, but that line of thinking breaks down at more fundamental operations like `PartialEq` or `Hash`. Having a different definition for equality fundamentally breaks the program if the two versions ever mix. On the flip-side, it's important that the author is allowed to declare the "correct" way to do something, e.g. in a smart pointer crate where the safety of the program relies on a correct implementation. If traits weren't program-wide, you're just kicking the bucket down the road from the library author having to do define every trait impl to every user defining every trait impl, which is even worse imo
Sure, maybe current Rust and current serde make it awkward to declare non-global serializers, but that doesn’t mean that coherence is a mistake.