chaotic3quilibrium
chaotic3quilibrium

Reputation: 5924

Why am I getting an error of "type arguments...do not conform to trait..." compiler error?

I have been stuck on a Scala (2.11.7) compiler error in IntelliJ (14.1.5) now for several hours. I have Googled, wracked my brain and experimented with a ton of variations but cannot seem to get around it.

I have taken the code context and clipped it down as small as I could (including clipping out any external library dependencies) to capture the domain I have been using to try and narrow down the issue. I thought I was using pretty straightforward idiomatic Scala; case objects, traits with type parameters, etc.

The fourth from the last line starting with abstract case class CoordinateRadian is the one generating this Scala compiler error:

Error:(128, 129) type arguments [Test.this.CoordinateRadian.unitBase.type,Test.this.LongitudeRadian,Test.this.LatitudeRadian] do not conform to trait Coordinate's type parameter bounds [U <: Test.this.Angle.UnitBase.Member,+O <: Test.this.Longitude[U],+A <: Test.this.Latitude[U]] abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, LongitudeRadian, LatitudeRadian] {

Here's the code with the compiler error:

package org.public_domain

class Test {
  object Angle {
    object UnitBase {
      trait Member
      case object RADIAN extends Member
      case object DEGREE extends Member
    }
    trait UnitBase[U <: Angle.UnitBase.Member] {
      def unitBase: U
    }

    object ZeroBase {
      trait Member
      case object LEFT extends Member
      case object MIDDLE extends Member
    }
    trait ZeroBase[U <: Angle.UnitBase.Member, Z <: Angle.ZeroBase.Member] extends Angle.UnitBase[U] {
      def zeroBase: Z
    }
  }
  trait Angle[U <: Angle.UnitBase.Member, Z <: Angle.ZeroBase.Member] extends Angle.ZeroBase[U, Z] {
    def theta: Double
  }

  trait Angle__ObjectBase {
    def basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member)
  }

  object AngleRadianMiddle extends ((Double) => AngleRadianMiddle) with Angle__ObjectBase {
    val basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member) =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): AngleRadianMiddle =
      new AngleRadianMiddle(theta) {
        def unitBase =
          basesAsTuple._1

        def zeroBase =
          basesAsTuple._2

        private def readResolve(): Object =
          AngleRadianMiddle(theta)

        def copy(thetaNew: Double = theta): AngleRadianMiddle =
          AngleRadianMiddle(thetaNew)
      }
  }
  abstract case class AngleRadianMiddle private[AngleRadianMiddle] (theta: Double) extends Angle[AngleRadianMiddle.basesAsTuple._1.type, AngleRadianMiddle.basesAsTuple._2.type] {
    def copy(thetaNew: Double = theta): AngleRadianMiddle
  }

  trait Itude[U <: Angle.UnitBase.Member] extends Angle[U, Angle.ZeroBase.MIDDLE.type] {
    val zeroBase =
      Angle.ZeroBase.MIDDLE
  }

  sealed trait Longitude[U <: Angle.UnitBase.Member] extends Itude[U]
  sealed trait Latitude[U <: Angle.UnitBase.Member] extends Itude[U]

  object LongitudeRadian extends ((Double) => LongitudeRadian) {
    val basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member) =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): LongitudeRadian =
      new LongitudeRadian(theta) {
        def unitBase =
          basesAsTuple._1

        private def readResolve(): Object =
          LongitudeRadian(theta)

        def copy(thetaNew: Double = theta): LongitudeRadian =
          LongitudeRadian(thetaNew)
      }
  }
  abstract case class LongitudeRadian(theta: Double) extends Longitude[LongitudeRadian.basesAsTuple._1.type] {
    def copy(thetaNew: Double = theta): LongitudeRadian
  }

  object LatitudeRadian extends ((Double) => LatitudeRadian) {
    val basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member) =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): LatitudeRadian =
      new LatitudeRadian(theta) {
        def unitBase =
          basesAsTuple._1

        private def readResolve(): Object =
          LatitudeRadian(theta)

        def copy(thetaNew: Double = theta): LatitudeRadian =
          LatitudeRadian(thetaNew)
      }
  }
  abstract case class LatitudeRadian(theta: Double) extends Latitude[LatitudeRadian.basesAsTuple._1.type] {
    def copy(thetaNew: Double = theta): LatitudeRadian
  }

  trait Coordinate[U <: Angle.UnitBase.Member, +O <: Longitude[U], +A <: Latitude[U]] {
    def longitude: O
    def latitude: A

    val x: O =
      longitude
    val y: A =
      latitude
  }

  object CoordinateRadian extends ((LongitudeRadian, LatitudeRadian) => CoordinateRadian) {
    val unitBase: Angle.UnitBase.Member =
      Angle.UnitBase.RADIAN

    def apply(longitude: LongitudeRadian, latitude: LatitudeRadian): CoordinateRadian =
      new CoordinateRadian(longitude, latitude) {
        private def readResolve(): Object =
          CoordinateRadian(longitude, latitude)

        def copy(longitudeNew: LongitudeRadian = longitude, latitudeNew: LatitudeRadian = latitude): CoordinateRadian =
          CoordinateRadian(longitudeNew, latitudeNew)
      }
  }
  //abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, Longitude[CoordinateRadian.unitBase.type], Latitude[CoordinateRadian.unitBase.type]] {
  abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, LongitudeRadian, LatitudeRadian] {
    def copy(longitudeNew: LongitudeRadian = longitude, latitudeNew: LatitudeRadian = latitude): CoordinateRadian
  }
}

You will notice the fifth line from the end of the file is a commented out line (and very similar to the fourth line from the end of the file). If you uncomment the fifth from the end line and then comment out the fourth from the end line and compile the code ("Build All" in IntelliJ), two errors will be emitted:

Error:(125, 67) overriding method longitude in trait Coordinate of type => Test.this.Longitude[Test.this.CoordinateRadian.unitBase.type]; value longitude has incompatible type abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, Longitude[CoordinateRadian.unitBase.type], Latitude[CoordinateRadian.unitBase.type]] {

Error:(125, 95) overriding method latitude in trait Coordinate of type => Test.this.Latitude[Test.this.CoordinateRadian.unitBase.type]; value latitude has incompatible type abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, Longitude[CoordinateRadian.unitBase.type], Latitude[CoordinateRadian.unitBase.type]] {

I may have just worked on this too long and now have a jaundiced eye. I haven't thought of any new ways to approach this in over an hour. SO, any guidance on what I am doing wrong would be greatly appreciated.

Upvotes: 1

Views: 485

Answers (1)

Alexey Romanov
Alexey Romanov

Reputation: 170733

Well, by constraints on Coordinate you need to have LongitudeRadian <: Longitude[CoordinateRadian.unitBase.type] (and similarly for latitude), which is wrong because LatitudeRadian.basesAsTuple._1.type isn't a subtype of CoordinateRadian.unitBase.type (the compiler knows only that LatitudeRadian.basesAsTuple._1 is an Angle.UnitBase.Member). If you just remove type annotations from basesAsTuple and unitBase, the compiler will infer the singleton types without problems.

class Test {
  object Angle {
    object UnitBase {
      trait Member
      case object RADIAN extends Member
      case object DEGREE extends Member
    }
    trait UnitBase[U <: Angle.UnitBase.Member] {
      def unitBase: U
    }

    object ZeroBase {
      trait Member
      case object LEFT extends Member
      case object MIDDLE extends Member
    }
    trait ZeroBase[U <: Angle.UnitBase.Member, Z <: Angle.ZeroBase.Member] extends Angle.UnitBase[U] {
      def zeroBase: Z
    }
  }
  trait Angle[U <: Angle.UnitBase.Member, Z <: Angle.ZeroBase.Member] extends Angle.ZeroBase[U, Z] {
    def theta: Double
  }

  trait Angle__ObjectBase {
    def basesAsTuple: (Angle.UnitBase.Member, Angle.ZeroBase.Member)
  }

  object AngleRadianMiddle extends ((Double) => AngleRadianMiddle) with Angle__ObjectBase {
    val basesAsTuple =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): AngleRadianMiddle =
      new AngleRadianMiddle(theta) {
        def unitBase =
          basesAsTuple._1

        def zeroBase =
          basesAsTuple._2

        private def readResolve(): Object =
          AngleRadianMiddle(theta)

        def copy(thetaNew: Double = theta): AngleRadianMiddle =
          AngleRadianMiddle(thetaNew)
      }
  }
  abstract case class AngleRadianMiddle private[AngleRadianMiddle] (theta: Double) extends Angle[AngleRadianMiddle.basesAsTuple._1.type, AngleRadianMiddle.basesAsTuple._2.type] {
    def copy(thetaNew: Double = theta): AngleRadianMiddle
  }

  trait Itude[U <: Angle.UnitBase.Member] extends Angle[U, Angle.ZeroBase.MIDDLE.type] {
    val zeroBase =
      Angle.ZeroBase.MIDDLE
  }

  sealed trait Longitude[U <: Angle.UnitBase.Member] extends Itude[U]
  sealed trait Latitude[U <: Angle.UnitBase.Member] extends Itude[U]

  object LongitudeRadian extends ((Double) => LongitudeRadian) {
    val basesAsTuple =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): LongitudeRadian =
      new LongitudeRadian(theta) {
        def unitBase =
          basesAsTuple._1

        private def readResolve(): Object =
          LongitudeRadian(theta)

        def copy(thetaNew: Double = theta): LongitudeRadian =
          LongitudeRadian(thetaNew)
      }
  }
  abstract case class LongitudeRadian(theta: Double) extends Longitude[LongitudeRadian.basesAsTuple._1.type] {
    def copy(thetaNew: Double = theta): LongitudeRadian
  }

  object LatitudeRadian extends ((Double) => LatitudeRadian) {
    val basesAsTuple =
      (Angle.UnitBase.RADIAN, Angle.ZeroBase.MIDDLE)

    def apply(theta: Double): LatitudeRadian =
      new LatitudeRadian(theta) {
        def unitBase =
          basesAsTuple._1

        private def readResolve(): Object =
          LatitudeRadian(theta)

        def copy(thetaNew: Double = theta): LatitudeRadian =
          LatitudeRadian(thetaNew)
      }
  }
  abstract case class LatitudeRadian(theta: Double) extends Latitude[LatitudeRadian.basesAsTuple._1.type] {
    def copy(thetaNew: Double = theta): LatitudeRadian
  }

  trait Coordinate[U <: Angle.UnitBase.Member, +O <: Longitude[U], +A <: Latitude[U]] {
    def longitude: O
    def latitude: A

    val x: O =
      longitude
    val y: A =
      latitude
  }

  object CoordinateRadian extends ((LongitudeRadian, LatitudeRadian) => CoordinateRadian) {
    val unitBase =
      Angle.UnitBase.RADIAN

    def apply(longitude: LongitudeRadian, latitude: LatitudeRadian): CoordinateRadian =
      new CoordinateRadian(longitude, latitude) {
        private def readResolve(): Object =
          CoordinateRadian(longitude, latitude)

        def copy(longitudeNew: LongitudeRadian = longitude, latitudeNew: LatitudeRadian = latitude): CoordinateRadian =
          CoordinateRadian(longitudeNew, latitudeNew)
      }
  }
  //abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, Longitude[CoordinateRadian.unitBase.type], Latitude[CoordinateRadian.unitBase.type]] {

  abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[CoordinateRadian.unitBase.type, LongitudeRadian, LatitudeRadian] {
    def copy(longitudeNew: LongitudeRadian = longitude, latitudeNew: LatitudeRadian = latitude): CoordinateRadian
  }
}

But to be honest, this looks like overuse of singleton types to me. I don't see why you need unitBase and basesAsTuple at all. I'd prefer to write

abstract case class LongitudeRadian(theta: Double) extends Longitude[RADIAN.type]

abstract case class CoordinateRadian private[CoordinateRadian] (longitude: LongitudeRadian, latitude: LatitudeRadian) extends Coordinate[RADIAN.type, LongitudeRadian, LatitudeRadian]

etc. Much less opportunity for being bitten by the compiler being unable to prove two objects are the same.

Upvotes: 1

Related Questions