Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upThe parameter ordering of `Option::map_or_else` is unintuitive. #1025
Comments
This comment has been minimized.
This comment has been minimized.
reem
commented
Mar 31, 2015
|
I agree that this ordering is unintuitive and it would be better if the |
This comment has been minimized.
This comment has been minimized.
|
Yes. I get this wrong every single time. |
This comment has been minimized.
This comment has been minimized.
|
To be honest I thought the order was always the other way around. Was it changed? |
This comment has been minimized.
This comment has been minimized.
|
@cmr I thought it was always the other way around too. That's what screwed me up and motivated me to open this issue. |
This comment has been minimized.
This comment has been minimized.
|
The order is currently chosen to be internally consistent with foo.map_or(some_value, |x| {
bar();
baz(x);
qux();
})vs. foo.map_or(|x| {
bar();
baz(x);
qux();
}, some_value)This isn't to say that we shouldn't change it, but we shouldn't consider this in isolation. |
This comment has been minimized.
This comment has been minimized.
|
@huonw That's understandable but still rather unintuitive. I would prefer to make it look nicer with a minor style tweak: foo.map_or(|x| {
bar();
baz(x);
qux();
},
some_value
)or even: foo.map_or(
|x| {
bar();
baz(x);
qux();
},
some_value
)This does get a little more right-drift but I think it's worth the concession for cleaner, more intuitive code. I use the docs all the time but if I have to consult them to figure out the right argument ordering for something as simple as an operation on a monad, it's going to severely impact my efficiency. |
This comment has been minimized.
This comment has been minimized.
|
I don't think I've ever screwed this one up. It just seems natural to me that the default value comes first. Probably because |
This comment has been minimized.
This comment has been minimized.
crazymykl
commented
May 31, 2015
|
@kballard, but even |
This comment has been minimized.
This comment has been minimized.
|
So obviously this can't be "fixed" in 1.x, and fixing it in 2.x would be a disaster. So... this bug isn't actionable? |
This comment has been minimized.
This comment has been minimized.
|
@Gankro I believe deprecating this for an alternative with a name that does not cause wrong associations with parameter ordering might make it actionable. But in general, ditto. |
This comment has been minimized.
This comment has been minimized.
|
@Gankro why would it be a disaster? People will get a compile error, and the fix is simple. |
This comment has been minimized.
This comment has been minimized.
This might be true, but it would be pretty devastating to have virtually all Rust projects break just because some people aren't satisfied with the |
This comment has been minimized.
This comment has been minimized.
|
@frewsxcv it's the re-ordering of arguments, not the renaming. Besides, people are free to stay with an ancient tool if doing a simple fix is too much effort. Some of these fixes could be automated even, especially simple ones like this. |
This comment has been minimized.
This comment has been minimized.
|
@tshepang This is not a good way for a language developer to act. Breaking client code in such a blatant way should not be taken so lightly. |
This comment has been minimized.
This comment has been minimized.
|
@Gankro I think "fixing mistakes and oversights" is supposed to be part of 2.x. Some (more important) stuff will be broken anyways, so we might as well break the smaller things as well. I think making things more intuitive is worth the pain. |
This comment has been minimized.
This comment has been minimized.
As stated above in previous comments, the argument order is intentional; it is neither a mistake nor an oversight. |
This comment has been minimized.
This comment has been minimized.
|
I hear you, but a mistake can happen whether or not there is intent. And as this issue has proven, people do not like this choice. |
This comment has been minimized.
This comment has been minimized.
|
Triage: |
This comment has been minimized.
This comment has been minimized.
|
Yup, this ship has sailed. |
abonander commentedMar 31, 2015
The signature of
Option<T>::map_or_elseis as follows:fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, def: D, f: F) -> UThis is highly unintuitive as the two closure parameters are in the reverse order of that suggested by the function's name. This means that anyone who tries to invoke it from memory, including myself earlier today, is going to run into a compiler error on the first try.
Example:
The above makes sense, logically. If the value is there, map it and return the result. Otherwise (implying a secondary operation), call a closure which will produce a substitute value. Even the documentation supports this logical progression:
However, trying to invoke the method this way will result in a compiler error because the no-arg closure is required to be first. The particular reasoning behind this design is not given, but I have found precedent in Haskell's
maybefunction:However, I don't think Haskell's intuition for parameter ordering can extend to Rust because Rust doesn't have currying, partial application, or (global) lazy evaluation. And even in Haskell the ordering isn't necessarily intuitive.
I am aware that this method and
Optionitself have both been marked asStable. However, I believe minor unintuities like this add up and ultimately reflect poorly on the user experience of the language as a whole, and should be addressed before Rust hits 1.0.I would like to note that I am willing to apply the effort to adjust this myself, as it's relatively trivial. However, because it's trivial, I am not sure if it requires an RFC or just a general community agreement.