The parameter ordering of `Option::map_or_else` is unintuitive

Closures as a final argument

work(because {|then|
   you_can_spread;
   a_longer_one_out;
   over_lines
} );

but tacking those arguments at the end looks much worse.

2 Likes

And map_or doesn't satisfy this demand?

In my cursory inspection of the Rust stdlib I have yet to find a function that takes a single closure and puts a non-closure argument after the closure argument. I admit that I haven't done an exhaustive search of the stdlib, but all of the functions I can think of off the top of my head that take closures put the closures last.

I don't know what sort of evidence would satisfy you. The fact that map_or follows the closure-last convention seems like it should be sufficient to demonstrate that this closure-last convention is considered stronger than the subjective "I think the arguments should be in a different order based on the function name" claim.

In general, when a function takes a closure argument, it goes last because that aids readability when using multi-line closures.

foo.bar(arg1, arg2, |x| {
    baz();
    quux();
});

is generally considered more readable than

foo.bar(|x| {
    baz();
    quux();
}, arg1, arg2);

Not only that, but because we already seem to have a strong convention of putting the closure last, following this convention everywhere means that users can rely on it and not screw up parameter order (e.g. in map_or they know the closure goes last, so the default value must go first).

To everyone here debating about the parameter ordering of map_or, that was nowhere in my original complaint. Its parameter ordering is also unintuitive but it somewhat makes sense from a style standpoint. As far as Iā€™m concerned, thatā€™s taking this discussion off-topic.

However, map_or_else takes two closures, so the style argument doesnā€™t really apply. Itā€™s going to be clunky either way around. Putting the closures in logical order should make sense then, even if it is inconsistent with map_or.

2 Likes

I donā€™t think so ā€“ and especially in the case of map_or_else thereā€™s likely to be more calls.

Iā€™d rather map_or and map_or_else be consistent. I also think map_or should take its closure argument last. Which means I prefer the status quo.

I think reasonable people are going to disagree on this, which probably means itā€™s not worthwhile to make a breaking change.

1 Like

That logic seems kinda circular:

A: Could we swap map_or's arguments into a more logical order? B: No, because we have a convention to put closure arguments last even if a different order were more logical. A: Can you show me an example where this convention has been followed at the expense of being logical? B: map_or

3 Likes

Given that we get argument labels to Rust at some point, the following versions of map_or and map_or_else (where the closure is not the last element and things are in logical order) become possible and in my opinion are much more readable:

let value = result.map(
    if_some: |a| {
        rabble;
        rabble;
        rabble;
        a + 10
    },
    else_value: 100
);

let value = result.map(
    if_some: |a| {
        rabble;
        rabble;
        rabble;
        a + 10
    },
    else_map: |a| {
        rabble;
        rabble;
        rabble;
        a + 100
    }
);
1 Like

For the record, I have bad memories of JavaScript functions that stick other arguments after closures - setTimeout, addEventListenerā€¦

1 Like

I donā€™t think function overload will be implemented, itā€™s just not rusty, so little chance we will see .map(if_some, else_value) and .map(if_some, else_map) as overloads.

I don't think that would be considered function overloading, because those argument labels take part in function name resolution. That is, the argument labels are kind of a part of the name of the function. (Given that they are mandatory, as opposed to optional, labels).

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.