Extension Methods Revisited

Whenever there’s a discussion on the topic of extension methods, I can’t help myself and have to share my idea about it :slight_smile:
How about we allow any method to be used as extension method, if it has the last parameter block singleton (where the receiver would be the only parameter in the block)?

It could look like this:

case class A(...)
def f(b: B, c: C)(a: A): D = ...
a.f(b, c) // de-sugars to f(b, c)(a)

The advantage of this is that it makes the very same methods methods easily chainable, in both scenarios:

  • using . as method application: sequence.map(plus1).filter(isEven)
  • using andThen (or >>> ) as method composition: map(plus1) andThen filter(isEven)
class Sequence[A](...)
...
def map(f: A => B)(s: Sequence[A]): Sequence[B] = ???
def filter(p: A => Boolean)(s: Sequence[A]): Sequence[A] = ???
...
sequence.map(plus1)
// de-sugars to `map(f)(sequence)`, since
// * `Sequence` doesn't have a member `map` and
// * `map(...)(s: Sequence[A])` is in scope

sequence.map(plus1).filter(isEven)
// de-sugars to `filter(isEven)(map(f)(sequence))`

// and these same function can also be used on their own very nicely, especially with chaining
map(plus1) andThen filter(isEven)

Currently we have to nest method calls in parentheses, which is cumbersome, e.g.
filter(isEven)(map(f)(sequence))

I think doing extensions methods as sketched here, would be simpler, less magical and even more flexible.
(previous posts 1 2 3)