Is it possible to create types like "NonEmptyString" in Scala 2.13?

In dotty there is opaque type where you can just define something like

opaque type NonEmptyString = String
object NonEmptyString:
  def apply(s: String): Either[Error, NonEmptyString] = ???

This ensures that the only way of creating a NonEmptyString is via the apply method of object NonEmptyString. Can something similar be done in Scala 2.13?

1 Like

Not as nice and concise, but, well…

2 Likes

You can encode the same thing with some extra boilerplate.

scala> trait NonEmptyString {
     |   type Type
     |   def apply(s: String): Option[Type]
     | }
trait NonEmptyString

scala> val NonEmptyString: NonEmptyString = new NonEmptyString {
     |   type Type = String
     |   def apply(s: String): Option[Type] = Option.when(s.nonEmpty)(s)
     | }
val NonEmptyString: NonEmptyString = $anon$1@5f7599fd

scala> val nes = NonEmptyString("foo")
val nes: Option[NonEmptyString.Type] = Some(foo)
1 Like

But the type of nes is not NonEmptyString instead it is Option[NonEmptyString.Type].

Yes, in this case NonEmptyString.Type is the equivalent of the opaque type NonEmptyString in dotty. Alternatively you could do

scala> trait Opaque {
     |   type NonEmptyString
     |   def NonEmptyString(s: String): Option[NonEmptyString]
     | }
trait Opaque

scala> val Opaque: Opaque = new Opaque {
     |   type NonEmptyString = String
     |   def NonEmptyString(s: String): Option[NonEmptyString] = Option.when(s.nonEmpty)(s)
     | }
val Opaque: Opaque = $anon$1@728f8064

scala> import Opaque._
import Opaque._

scala> val nes: Option[NonEmptyString] = NonEmptyString("foo")
val nes: Option[Opaque.NonEmptyString] = Some(foo)

Top level objects is not possible in Scala 2.13. So the code,

val NonEmptyString: NonEmptyString = new NonEmptyString {
        type Type = String
        def apply(s: String): Option[Type] = Option.when(s.nonEmpty)(s)
      }

Will have to go inside an object and the type will no longer be NonEmptyString.Type. It will instead be <object-name>.NonEmptyString.Type

True. And the same would be true if Scala 2.13 had the opaque types feature. The opaque type and its companion object couldn’t be top level either.

1 Like

Package object to the rescue, perhaps?

1 Like