# Polymorphic eta-expansion

Hello,
In the conext of my master semester project, I’m implementing Polymorphic eta-expansion, I would like to have your feedback!

### What it is:

Polymorphic eta-expansion is the step of (automatically) converting a polymorphic method, such as:

``````def id[T](x: T) = x
// type of id: [T](T): T
``````

To a value of polymorphic function type, such as:

``````[T] => (x: T) => ident[T](x)
// type: [T] => T => T
``````

The full technical details can be found it this PR to the scala 2 doc (as there is no scala 3 doc yet):

Polymorphic eta-expansion allows us to write shorter, clearer code by removing boilerplate:

### Simple Examples:

(taken from the new test file)

``````// Type [T] => T => T, used to be Any => Any
val valId /*[T] => T => T*/ = id
val valValId: [T] => T => T = valId1

// recall (tu: Tuple).map[F[_]](f: [t] => (x\$1: t) => F[t]): Map[Tuple, F]
val mapped: (Int, String, Char) = (1, "two", '3').map(id)

val optioner: [T] => T => Option[T] = Option.apply

type Z
type X <: Z
type Y >: X <: Z

val valIdxyz: [T >: X <: Y ] => X => Z = id

def monoPair[T](x: T)(y: T): (T, T) = (x, y)
val valMonoPair: [T] => T => T => (T,T) = monoPair

def protoPair[T](x: T): [U] => (U) => (T, U) = [U] => (y: U) => (x,y)
val valProtoPair1: [T] => (T) => [U] => U => (T, U) = protoPair
``````

(The change from `valId` having type `Any => Any` to having `[T] => T => T` should not break anything, as `valId` can refer to `valId[Any]` throught type Inferrence.)

### Real-world examples:

In this part of the shapeless library, the explicit conversion at line 511 can be replaced by the more succint:

``````// before:
given Pure[Id] = mkPure([T] => (t: T) => t)
// now:
given Pure[Id] = mkPure(identity)
``````

Another similar case can be found at line 244 (`G.pure`)

In the neighboring file `instances.scala`, no obvious example can be found, there is however code duplication of:

``````[t] => (tc: TypeClass[t]) => tc.another
``````

Which given a function like:

``````def takeAnother[T](tc: TypeClass[T]) = tc.another
``````

Could be replaced, for example in this line:

``````val otherInst = inst.mapK(takeAnother)
``````

### Side Effects:

It was not possible to write something like the following: (works if `() =>` is inserted)

``````val noneFun: [T] => Option[T] = [T] => None
``````

Fortunately, there is a PR to address this exact problem, so I rebased on top of:

Unfortunately, this brings the "`[T] => (T => T)` is not the same as `[T] => (T) => T`" problem
To fix it, all poly eta-expanded methods are brought to a common, unique form: `PolyFunction{def apply[<tArgs>]: <ret>}` where `<ret>` in the above would be `T => T`.
(Unlike before, where `apply` could have more than one parameter clause)

As a consequence:

• all polymorphic values erase to `Function0` (except manual creation of `PolyFunction` subclasses)
• tasty backward compatibility is broken

### Ways in which it could get extended:

Find a way to make the new `PolyFunction` behaviour as backwards compatible as possible, @smarter had some ideas and might be working on it in the future

Keep “universality” of wildcard:

``````val fromWildcard: [T] => T => T = identitiy(_)
``````

Keep “universality” of lambdas without type ascription:

``````val fromLambda: [T] => T => T = y => y
``````

Create type lambdas through wildcard:

``````val fromWildcardType: [T] => T => T = identitiy[_](_)
``````

Would be particularly useful in cases where there is more than one type parameter, which is not particularly frequent, but could be:

### Parallel project: Interweaved Clauses

If this and interweaved clauses (forum, doc) are added, the following should work without any additions:

``````def pair[T](x: T)[U](y: U) = (x, y) //method type [T](T)[U](U): (T, U)
val valPair: [T] => T => [U] => U => (T,U) = pair
val pairFromSecond: [U] => U => (Int, U) = pair(42)
``````

### Conclusion

I hope you find this feature useful, and am happy to answer any questions,
I would appreciate feedback as this is my first language contribution to scala !

18 Likes

Errata: Should be “master semester project”
I can’t edit my posts, if someone could grant me this power for this specific post, I would be grateful