0

I have the following type class definition -

trait ToBigInt[A] {
  def toBigInt(n: A): BigInt
}

object ToBigInt {
  def apply[A](implicit t: ToBigInt[A]): ToBigInt[A] = t

  implicit val toBigIntByte: ToBigInt[Byte] = (x: Byte) => BigInt(x)

  implicit val toBigIntShort: ToBigInt[Short] = (x: Short) => BigInt(x)

  implicit val toBigIntInt: ToBigInt[Int] = (x: Int) => BigInt(x)

  implicit val toBigIntLong: ToBigInt[Long] = (x: Long) => BigInt(x)

  implicit val toBigIntBigInt: ToBigInt[BigInt] = identity _

  implicit class RichToBigInt[A: ToBigInt](value: A) {
    def toBigInt: BigInt = ToBigInt[A].toBigInt(value)
  }
}

Notably, within the ToBigInt object I have included an implicit class which contains the toBigInt method.

Unfortunately, the following code does not compile -

import FromBigInt._
import ToBigInt._

final class Unsigned[A: BoundedIntegral] private (val value: A) {
  def toBigInt: BigInt =
    BoundedIntegral[A].toBigInt(value) - BoundedIntegral[A].toBigInt(BoundedIntegral[A].minValue)

  override def toString: String = toBigInt.toString

  override def equals(that: Any): Boolean = that match {
    case unsigned: Unsigned[A] => toBigInt == unsigned.toBigInt
    case _ => false
  }
}

object Unsigned {
  def apply[A: BoundedIntegral, N: ToBigInt](n: N): Unsigned[A] = {
    assert(n.toBigInt >= BigInt(0), "Integer cannot be negative")
    assert(n.toBigInt <= BoundedIntegral[A].maxValue.toBigInt * 2 + 1, "Integer out of range")
    new Unsigned[A]((n.toBigInt - BoundedIntegral[A].minValue.toBigInt).fromBigInt)
  }
}

trait BoundedIntegral[A] extends Bounded[A] with ToFromBigInt[A]

object BoundedIntegral {
  def apply[A](implicit b: BoundedIntegral[A]): BoundedIntegral[A] = b
}

[error] Unsigned.scala:24:14: value toBigInt is not a member of type parameter N
[error]     assert(n.toBigInt >= BigInt(0), "Integer cannot be negative")
[error]              ^
[error] Unsigned.scala:25:14: value toBigInt is not a member of type parameter N
[error]     assert(n.toBigInt <= BoundedIntegral[A].maxValue.toBigInt * 2 + 1, "Integer out of range")
[error]              ^
[error] Unsigned.scala:25:54: value toBigInt is not a member of type parameter A
[error]     assert(n.toBigInt <= BoundedIntegral[A].maxValue.toBigInt * 2 + 1, "Integer out of range")
[error]                                                      ^
[error] Unsigned.scala:26:24: value toBigInt is not a member of type parameter N
[error]     new Unsigned[A]((n.toBigInt - BoundedIntegral[A].minValue.toBigInt).fromBigInt)
[error]                        ^
[error] Unsigned.scala:26:63: value toBigInt is not a member of type parameter A
[error]     new Unsigned[A]((n.toBigInt - BoundedIntegral[A].minValue.toBigInt).fromBigInt)

On the other hand, intellij has no issue with the code. What is the issue with this code?

Update: I have narrowed down the issue -

package unsigned

trait ToBigInt[A] {
  def toBigInt(n: A): BigInt
}

object ToBigInt {
  def apply[A](implicit t: ToBigInt[A]): ToBigInt[A] = t

  implicit class RichToBigInt[A: ToBigInt](value: A) {
    def toBigInt: BigInt = ToBigInt[A].toBigInt(value)
  }

  def test1[A: ToBigInt](n: A): BigInt = n.toBigInt
}

trait FromBigInt[A] {
  def fromBigInt(n: BigInt): A
}

object FromBigInt {
  def apply[A](implicit t: FromBigInt[A]): FromBigInt[A] = t

  implicit class RichToBigInt(value: BigInt) {
    def fromBigInt[A: FromBigInt]: A = FromBigInt[A].fromBigInt(value)
  }
}

object Test1 {
  import ToBigInt._
  def test1[A: ToBigInt](n: A): BigInt = n.toBigInt
}

object Test2 {
  import ToBigInt._
  import FromBigInt._
  def test2[A: ToBigInt](n: A): BigInt = n.toBigInt
}

The unused import import FromBigInt._ in the Test2 object is causing a compile time error.

 ....:37:44: value toBigInt is not a member of type parameter A
[error]   def test2[A: ToBigInt](n: A): BigInt = n.toBigInt
[error]                                            ^
[error] one error found
Michael T
  • 1,033
  • 9
  • 13

1 Answers1

0

I don't think you're using implicits the way they're supposed to.

Declaring the method apply in Unsigned as def apply[A <: BoundedIntegral[_], N](n: N)(implicit bigInt: ToBigInt[N]) seems to fix this part of the compilation

C4stor
  • 8,355
  • 6
  • 29
  • 47