Search code examples
scalashapelessrefined

Trying to keep types unwrapped when using refined


I am trying to use refined to create smart constructors based on primitives and avoid wrapping since same types might be used in large collections. Am I doing this right? Seems to work but a bit boilerplaty

    type ONE_Pred = = MatchesRegex[W....
    type ONE = String @@ ONE_Pred
    type TWO_Pred = OneOf[...
    type TWO = String @@ TWO_PRED 

and then

 case class C(one:ONE, two:TWO)
 object C {
  def apply(one:String, two:String):Either[String, C] = 
  (
   refineT[ONE_Pred](one),
   refineT[TWO_Pred](two)
  ).mapN(C.apply)
}

Solution

  • Refined has a mechanism for creating a companion-like objects that have some utilites already defined:

    type ONE = String @@ MatchesRegex["\\d+"]
    object ONE extends RefinedTypeOps[ONE, String]
    

    Note that:

    1. You don't need a predicate type to be mentioned separately
    2. It works for both shapeless tags and refined own newtypes. The flavor you get is based on the structure of type ONE.

    You get:

    • ONE("literal") as alternative to refineMT/refineMV
    • ONE.from(string) as alternative to refineT/refineV
    • ONE.unapply so you can do string match { case ONE(taggedValue) => ... }
    • ONE.unsafeFrom for when your only option is to throw an exception.

    With these "companions", it's possible to write much simpler code with no need to mention any predicate types:

    object C {
      def apply(one: String, two: String): Either[String, C] =
        (ONE.from(one), TWO.from(two)).mapN(C.apply)
    }
    

    (example in scastie, using 2.13 with native literal types)