Description
In default Scala 2, we have a way to alias types. This is great as a way to make code more readable, but if your type logically has a more limited range of support then the type won't enforce this. Or if the type you are working with is used in different places to mean different things, then implicits wont know what to pick.
Opaque type aliases from Scala 3 provide type abstraction without any overhead. In Scala 2, a similar result could be achieved with value classes, but it has limitations and enforces "boxed" syntax, e.g.:
final case class ID(value: String) extends AnyVal
Seq[ID](...).forEach{ id=>
println("Sth sth" + id.value)
}
Seq[String](ID("asdsadas").value)
My proposition allows to define quasi-opaque type without runtime overhead and with full IDE support.
object ID extends Opaque.Default[String]
Seq[String](ID("DASDAS"))
/*
type mismatch;
found : CastableTest.this.ID.Type
(which expands to) com.avsystem.commons.opaque.Opaque.Hidden[String,CastableTest.this.ID.Tag]
required: String
*/
Seq[ID.Type]("DASDAS")
/*
type mismatch;
found : String("DASDAS")
required: CastableTest.this.ID.Type
(which expands to) com.avsystem.commons.opaque.Opaque.Hidden[String,CastableTest.this.ID.Tag]
Seq[ID.Type]("DASDAS")
*/
Seq[ID](...).forEach{ id=>
println("Sth sth" + id)
}
object ID2 extends Subopaque.Default[String]
Seq[String](ID2("DASDAS")) //ok
Opaque
is equivalent to
opaque type T = Original
SubOpaque
is equivalent to:
opaque type T <: Original = Original
in Scala 3