milessabin / shapeless

Generic programming for Scala

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

_0 as defined is somehow causing extreme compile times

jdrphillips opened this issue · comments

Scala versions observed on: 2.13.8, 2.13.9-bin-f11f1f7

The behaviour

This is a very bizarre thing I have noticed. If I use shapeless' definition of Nat in calculations I can achieve very fast compile times on Sum if I do not use shapeless' _0

Here is the code:

private[testing] object NatTest {
  import shapeless.Nat
  import shapeless.Succ

  // Here is the code I swap out: Either use shapeless' _0 or define my own identical:
  // import shapeless.nat._0
  class _0 extends Nat with Serializable {
    type N = _0
  }

  // Because I am using my own _0, I must define my own Sum. This is the same as shapeless' but typelevel only
  trait Sum[A <: Nat, B <: Nat] { type Out <: Nat }
  object Sum {
    type Aux[A <: Nat, B <: Nat, Out0 <: Nat] = Sum[A, B] { type Out = Out0 }
    implicit def zeroCase[A <: Nat]: Sum.Aux[_0, A, A] = ???
    implicit def recursive[A <: Nat, B <: Nat](
      implicit sum: Sum[A, Succ[B]]
    ): Sum.Aux[Succ[A], B, sum.Out] = ???
  }

  def sum[A <: Nat, B <: Nat](implicit s: Sum[A, B]): s.Out = null.asInstanceOf[s.Out]

  // Some numbers I want to use:
  type _12 =
  Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[
    _0
  ]]]]]]]]]]]]

  type _15 =
  Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[
    _0
  ]]]]]]]]]]]]]]]

  type _27 =
  Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[Succ[
  Succ[Succ[Succ[Succ[Succ[Succ[Succ[
    _0
  ]]]]]]]]]]]]]]]]]]]]]]]]]]]
}

Note I am using shapeless' own Nat and Succ. I have had to define my own Sum to use my own _0, but it is the same algorithm shapeless uses. Note that my own definition of _0 is the same as shapeless, copy+pasted.

Here's the sum I am testing against:

  sum[_15, _12]: _27

If I use shapeless.nat._0 the sum takes approx 120s to compile on my machine.

If I use NatTest._0 the sum takes approx 0-1s(!) to compile on my machine.

I have tried the following:

  • _0 defined in separate object
  • _0 defined in separate package
  • Running my above code in a branch of shapeless itself (so not relying on a library jar)

I observe the same behaviour everywhere: shapeless.nat._0 causes 120x compile times compared to other scenarios

Scala versions observed on: 2.13.8, 2.13.9-bin-f11f1f7

You can see the behaviour for yourself in my shapeless fork: https://github.com/jdrphillips/shapeless/blob/feature/nat-test/core/src/main/scala/shapeless/NatTest.scala

The expectation

I would expect my code to behave the same no matter where I defined _0

Resolved by using shapelss._0 and not the alias shapeless.nat._0