These problems are partially sidestepped by my proposal to require ||
before a partial application: in this syntax, it is clear that || foo().bar(_)
becomes |x| foo().bar(x)
. However, it's not clear what || || foo(_, _)
should do; if I had to guess, I'd say || |x, y| foo(x, y)
.
Looking at prior art, Scala jumped this ship a while ago, since it uses the "wunderbar" for both purposes:
// define mutable foo to have the default value for `Int`
var foo: Int = _
// don't bind parts of a match
(foo, bar) match {
case (0, _) => println("zero!")
case _ => println("something else")
}
// erased type parameter, equivalent to Java's Foo<?>
// (NOT please-infer-the-paramter-for-me, unlike Rust)
def foo: Foo[_] = ..
// equivalent to xs.map { x, y => x + y }, the syntax we're
// discussing today
xs.map(_ + _)
I tend to read _
as "I want a variable here but I don't want to give it a name so I'll let the compiler make one for me". This is a valid interpretation of things like let _ = ..;
, only that you can't pronounce that "variable", so it can be elided.
This is just my personal taste, but the $
is kind of ugly.
I feel like ?
is just asking for readability trouble: imagine something like iter.map(?.foo()?.bar())
, or worse still, iter.map(-?)
! I think a lot of us are trained to think Result
-propagation when we see ?
and it'd be pretty jarring!
Swatches for the above syntaces (though I think we're just arguing about paint colors at this point).
iter.map(foo(1, $, $));
iter.map(-$);
iter.map($ + $);
iter.map($.foo($));
iter.map(foo(1, ?, ?));
iter.map(-?);
iter.map(? + ?);
iter.map(?.foo(?));
// for comparison, my proposal:
iter.map(|| foo(1, _, _));
iter.map(|| -_);
iter.map(|| _ + _);
iter.map(|| _.foo(_));