I am new to scala and the refined library but I am trying to create two refined types based on UUIDs.
In order to do so, I did this (Note: Uuid in this case comes from eu.timepit.refined.string.Uuid):
type UuidPredicate = Uuid
type UuidA = String Refined UuidPredicate
type UuidB = String Refined UuidPredicate
However, it appears as though this only creates aliases, and therefore there is no type safety.
So if I had a constructor like Product(a UuidA, b UuidB)
and proceeded to do something like this:
val myUuid: UuidA = "9f9ef0c6-b6f8-11ea-b3de-0242ac130004"
val Product = Product(myUuid, myUuid)
It would compile and run properly. Is there anyway to ensure this is not the case? If a variable is created as one type, how can I make it so it only be used as that particular refined type, even though the types are fundamentally the same?
The simplest is to introduce different data types
case class UuidA(value: String Refined UuidPredicate)
case class UuidB(value: String Refined UuidPredicate)
You can't make UuidA
, UuidB
extend AnyVal
because Refined
already extends AnyVal
and Scala doesn't allow nested value classes.
If you prefer to avoid runtime overhead of wrapping with UuidA
, UuidB
you can try @newtype
as @LuisMiguelMejíaSuárez adviced
import io.estatico.newtype.macros.newtype
@newtype case class UuidA(value: String Refined UuidPredicate)
@newtype case class UuidB(value: String Refined UuidPredicate)
Or try to add more tags
import eu.timepit.refined.api.Refined
import eu.timepit.refined.string.Uuid
import eu.timepit.refined.auto._
import shapeless.tag
import shapeless.tag.@@
type UuidPredicate = Uuid
type UuidString = Refined[String, UuidPredicate]
type TagA
type TagB
type UuidA = UuidString @@ TagA
type UuidB = UuidString @@ TagB
case class Product(a: UuidA, b: UuidB)
val myUuid: UuidA = tag[TagA][UuidString]("9f9ef0c6-b6f8-11ea-b3de-0242ac130004")
// val product = Product(myUuid, myUuid) // doesn't compile
val myUuid1: UuidB = tag[TagB][UuidString]("9f9ef0c6-b6f8-11ea-b3de-0242ac130004")
val product1 = Product(myUuid, myUuid1) // compiles