Remix.run Logo
jerf 3 days ago

A lot. You're not seeing it precisely because it isn't under the streetlight, because it is currently impossible: https://en.wikipedia.org/wiki/Streetlight_effect

This really amps up the composibility of a lot of systems and libraries. It would be awesome if there was a "free" way to do this. Unfortunately no one has found one yet; the posted article is a pretty good overview of that problem.

Also, bear in mind that no matter what solution you are looking at, it's generally crate_c that wants to create the implementation for crate_a's type using a trait in crate_b, so it isn't as bad as the "behavior of crate_a or crate_b would change if they link one to another", which would indeed be horrifying. crate_c has to be involved somehow in the build, without that crate_a and crate_b carry on completely normally. When it's the end-user application doing the trait, at least the end-user can manage it; the core problem arises when crate_c is third-party, and user wants to use that and also crate_d, which also implements a train from crate_b on crate_a's type. At that point you have a pretty big issue; I would characterize implicits as a way of managing the problem, but not really a "solution". It is not clear there is a "solution".

And there is clearly a problem; the Haskell community rammed into this problem decently hard a long time ago, back when they were smaller than they even are today, and certainly smaller back then than the Rust ecosystem as it stands today. The phase transition from theoretical problem to real problem happens in an ecosystem an order of magnitude or two smaller than the current Rust ecosystem, which is itself likely to grow yet by another order or two at least over its lifespan.

ivanjermakov 3 days ago | parent [-]

Love to see a problem from the frontline of computer science as an actual practical problem solution to which would greatly benefit languages' semantics.

Regarding conflicting impls in crate_c and crate_d: what is wrong with Haskell's approach of grading impls by their specialty (e.g. Show Int is more specific than Show a so prior instance would be used if matches) and only throwing an error if it's ambiguous to the compiler which instance to use?

I see that this is not sufficient, since crate_e can't do anything about conflicting impls in crate_c and crate_d. Having to explicitly import impls does not spark joy. The problem is more convoluted than I thought!

I'm very interested in this topic since I'm working on a language that features traits and thus have a chance to "fix" it.

P.S. found another good article on this topic: https://www.michaelpj.com/blog/2020/10/29/your-orphans-are-f...

jerf a day ago | parent [-]

"Regarding conflicting impls in crate_c and crate_d: what is wrong with Haskell's approach of grading impls by their specialty"

You can still get surprising errors later in crate_c and crate_d when crate_e adds something, which is suboptimal.

I'm not saying all solutions are equally good or bad, just that there isn't a known perfect solution yet. If you accept the principle that "Writing some more code into module E shouldn't cause new errors to appear in C and D", which is a reasonable thing to want in a system, then this isn't a perfect solution.