Skip to content

Potential Issue with Opaque Types #5455

@adamgfraser

Description

@adamgfraser

I was playing a bit with opaque types and encountered what at least to me seems like some strange behavior. If I define an opaque type Nat and then want to refer to that type in a function definition at use site I need to use Nat.Nat. Nat seems to only refer to the companion object versus the opaque type itself. This is inconsistent with the treatment of other types. For example, if I defined Nat as a case class with a companion object then I could use Nat to refer to the type itself in a function definition. This seems less than ideal since I think one of the goals of opaque types was for them to be treated like any other type at use site. Is this intended behavior or a bug? Example below:

object Library {

  opaque type Nat = Int

  object Nat {
    def apply(n: Int): Nat = {
      require(n >= 0)
      n
    }
    def times(x: Nat, y: Nat): Nat = x * y
    def toInt(n: Nat): Int = n

    implicit class NatOps(val self: Nat) extends AnyVal {
      def *(other: Nat): Nat = self * other
      def toInt: Int = self
    }
  }
}

object User extends App {
  import Library._

  val x = Nat(3)
  val y = Nat(4)

  val a = x * y               // inferred type is Library.Nat.Nat
  val b = double1(x)          // inferred type is Library.Nat
  val c = double2(x)          // inferred type is Library.Nat.Nat

  assert(a.toInt == 12)       // works
  //assert(b.toInt == 6)      // error: toInt is not a member of Library.Nat
  assert(c.toInt == 6)        // works

  //def double0(n: Nat): Nat = n * Nat(2)       // error

  def double1(n: Nat.Nat): Nat = n * Nat(2)     // output type is incorrect

  def double2(n: Nat.Nat): Nat.Nat =n * Nat(2)  // works
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions