Rust doesn't have higher kinded types, every closure has a unique type that implements up to three different traits, and it has imperative control flow structures that don't exist in Haskell, et al.
By the time you've solved all these problems, you've moved away from monads to full-blown delimited continuations, one small step away from an effect system. And nobody really knows how to make that work while still providing Rust/C++-like "zero cost abstraction."
It might be nice, but it's not at all clear that it would even be "just one interface" anyway.
This wasn't directed at Rust in particular; many languages have these kinds of operators and even more are trying to propose them and I wonder if people just don't see the big picture and/or don't care. You can have a good and productive language without seeing the big picture or maybe realizing too late, but it's not a paragon of good design. It's definitely a design smell to introduce special-cased operators for these things.
With that said, I really like Rust and I think it's an excellent language. This particular thing irks me because a lot of the people who'd exalt this kind of feature usually simultaneously argue that monads are somehow not relevant, while not realizing it's contradictory.
The people who made these choices, and the people who "exalt" them, thus cannot fairly be described as "just don't see the big picture," "don't care," or "not realizing it's contradictory." And until someone has figured out a way to combine a general monadic interface (or more likely, some other method for orchestrating continuations) with Rust-like zero-cost abstractions, these features continue to be "cool" "in their own right." :)
From the standpoint of "How do we handle things that behave like these things (monads) in a general way?" it's certainly not a good one. It's not that I'm saying that Rust is badly designed overall, but like other languages with these operators it exhibits this particular design smell. It's not really debatable that this kind of special-casing is bad design and lack of foresight or a general lack of caring about this thing in particular.
It's also fine not to care about it, just as it's fine to not care about generics if one so chooses.
> The people who made these choices, and the people who "exalt" them, thus cannot fairly be described as "just don't see the big picture," "don't care," or "not realizing it's contradictory." And until someone has figured out a way to combine a general monadic interface (or more likely, some other method for orchestrating continuations) with Rust-like zero-cost abstractions, these features continue to be "cool" "in their own right." :)
I think you're reading a bit more into this than I intended and I guess that's fair. I don't think it's that big a deal that Rust lacks a way to generalize over this concept, but let's not pretend it's a good thing. At which nth special operator for some variant of this behavior would you consider this to be generally not a great design choice? It's either some N or where you intentionally limit this simply because making a bunch of operators is a silly proposition. Either of those cases mean a failure in design. Is it a major one that matters to everyone? No, but it's a shortcoming.
It's fine for languages to make trade-offs and not be perfect in every way, I don't think it's terribly productive to not see obvious shortcomings just because we like something.
That's what I'm reacting to, mostly. But also to the idea that it's some kind of universal, uncontroversial positive for a language to abstract over an unbounded number of implementations of monads.
In a tautological sense, of course, if a language doesn't support feature X that's a problem for people who want to use feature X. But we don't write programs to use language features- we write programs to solve problems.
That is, one could argue that feature X has too much complexity to be worth having in a language, and that solving the same problems another way (or not at all) is better. This is different from the point I made up-thread, and I'm still not trying to make it about monads. But it does seem to me that classifying every tradeoff as a shortcoming presupposes that if a language could support every single possible feature it would be perfect, which is also a silly proposition.
But it's pretty unreasonable to call it _bad design_ in a vacuum, as if there are no obstacles to a more generic design. The reason something like do-notation wasn't chosen is that nobody figured out a way to implement it without major trade-offs. So the alternative you're championing here either isn't possible within the constraints of the language, or the solution hasn't been discovered yet. The `?` operator was a pragmatic compromise.
I'm with you 100% that it is a shortcoming, but you can't really call it bad design given the reality of the situation. Compromises aren't bad design.