Reputation: 157
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?
Upvotes: 2
Views: 544
Reputation: 51683
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
Upvotes: 2