Implied bounds by scalexm · Pull Request #2089 · rust-lang/rfcs (original) (raw)

So I am very much in favor of this general idea (and have been for some time now...since 2014, apparently...sheesh!). And I am very excited about the work that @scalexm has done to realize it in practice, formalize it, and work through some of the tricky implications.

To my mind, the primary goal of this RFC is to eliminate the need to copy-and-paste redundant sets of bounds when implementing types (a random example). The RFC should also have the effect, however, of generally improving ergonomics, as also described in RFC #1927 and numerous Rust issues (e.g. rust-lang/rust#20671). Further, a nice side-effect of adopting the strategy laid out in this RFC will be fixing some of the various limitations in rustc's implementation (e.g., rust-lang/rust#20775). Overall, I think the "guts" of this RFC are a slam dunk! I'm inclined to move quickly to FCP.

However, there were some interesting "judgement calls" raised in the discussion in the lang team, and I think it would be helpful to get some feedback on these points. I think there were two such concerns raised (both related):

  1. The first is the most obvious. It concerns the fact that -- if this RFC lands -- removing bounds becomes a backwards incompatible thing to do. This might be considered surprising (although it's actually true today, for T: 'x bounds at least). This also means that sometimes to "disclose" some aspects of your private fields in your struct signature which you can then cannot remove, even if those private fields go away (as @scalexm noted).
  2. The other is one of predictability. This RFC definitely enables some kinds of "long-range" inference. For example, if I have fn foo<T>(x: Bar<T>, y: T), where Bar<T: Iterator>, I can then invoke y.next(), even though I don't (directly) have T: Iterator bound. This is natural when I am "close" to the definition of Bar, but perhaps it is surprising elsewhere (another way to look at it: removing the Bar<T> argument makes calls to y.next() stop working).
    • We have tried to limit this to the cases where we already have precedent (supertraits, inferring T: 'x requirements): informing function and impl bodies by their inputs. But this is obviously going further than we currently go.

To be honest, I think both of these things -- but especially the latter! -- are somewhat hard to judge in the abstract. They feel like concerns we might experiment with during the stabilization period. That said, we considered various ways to ameliorate these concerns, all basically focused on limiting the scope of the implied bounds:

Of the two, crate-local feels a bit better to me. We have plenty of precedent for crate-local rules of this kind, but none at all (very little?) for the other kind. Personally, though, I am inclined to start with the full version and see how it feels (e.g., within rustc and elsewhere). I think that if it feels surprising, we will start to notice it. That said, I think when we stabilize, if we still feel we want more experience, it would be reasonable to have a separate feature-flag for "cross-crate implied bounds".