Remix.run Logo
dathinab 14 hours ago

This isn't a new discussion it was there around the early rust days too.

And IMHO coherence and orphan rules have majorly contributed to the quality of the eco system.

MeetingsBrowser 14 hours ago | parent [-]

can you elaborate on how have they contributed to the quality of the ecosystem?

dathinab 13 hours ago | parent | next [-]

there is no good way to handle colliding implementations. Both from parallel crates and due to changes over time.

Without it you can have many many additional forms of breakage. Worse you can have "new" breakage between two 3rd party crates without either of them changing due to some impl in a common ancestor changing (e.g. std) and this affecting two wild card implementations in each, now leading to an overlap.

When you have an overlap there are two options:

- fail compilation, but as mentioned this could be caused by a non breaking change in std in two in theory unrelated 3rd party dependencies

- try to choose one of the implementations. But that now gets very messy in multiple points: a) Which impl. to choose when. b) The user knowing which is chosen. c) Overlap with interactions with stuff like double dispatch, thread local variables, and in general side effects. The issues here are similar to specialization (and part why that is stuck in limbo), but a magnitude more complex as specialization is only (meant) for optimizations, while this can be deeply different behavior. Like `foo.bar()` with the same `use Bar as _;` might in one context return an `u32` and in another a `String`

In many other ecosystems it's not uncommon to run into having issues where certain libraries can't be used together at all. In rust that is close to not a thing (no_mange collisions and C dependencies are the only exception I can think of).

Similar, in my experience the likely hood of running into unintended breaking changes is lower in the rust ecosystem then e.g. python or js, that is partially due to coherence rules forcing a more clean design.

Also people are forced to have a somewhat clean dependency tree between crates in ways not all languages requires. This can help with incremental builds and compiler time, a area rust needs any help it can get. (As a side note, clean dependency structures in your modules can (sometimes) help will rust better parallelizing code gen, too.)

So overall it I think it's good.

Through it can be very annoying. And there is some potential for improvement in many ways.

---

EDIT: sorry some keyboard fat-fingering somehow submitted a half written response without me pressing enter...

EDIT 2: Fix spelling and sentence structure.

MeetingsBrowser 10 hours ago | parent [-]

> In many other ecosystems it's not uncommon to run into having issues where certain libraries can't be used together at all.

The same problem exists in Rust, but from the other side.

If I use serde for serialization I am effectively locked in to using crates that implement serde traits (or do newtype hacks to define them myself).

If I want to use something more niche than serde, I essentially lose access to all the popular crates as they only implement serde traits.

simonask 9 hours ago | parent | next [-]

Newtypes aren’t hacks, they’re perfectly acceptable in my opinion. Especially if you’re willing to also use a crate like `derive_more`.

dathinab 9 hours ago | parent | prev [-]

for me that is a completely different problem,

one you solve when initially writing code (so you can properly account for it and control it)

instead of a problem which can blow up when you update a package for a very pressing security fix

in the end it a question what is more important, stability or the option to monkey patch functionality into your dependencies without changing them

and given that you can always non-monkey patch crates (rust makes vendoring dep. relatively easy in case upstream doesn't fix things) I prefer the stability aspect (through if you do patch crates you re-introduce many of the issues in a different place, with the main difference of there being a chance to upstream you changes)

dap 8 hours ago | parent | prev [-]

I've never once pulled in a new dependency and had the program fail to compile just by virtue of that dependency being present [because both my code and the new code both impl'd the same trait on the same type in some other code]. Because that can't happen because of coherence. (Right?)

It's so easy to forget about the problems we don't have because of the (good) choices people have made in the past.