I use Shapeless's tagged types to get nice typesafe primitives to pass through my business logic. Defining these types started with a simple:
sealed trait MyTaggedStringTag
type MyTaggedString = String @@ MyTaggedStringTag
But I've added a good bit of helper logic to this, and now my definitions look more like:
sealed trait MyTaggedStringTag
type MyTaggedString = String @@ MyTaggedStringTag
object MyTaggedString {
def fromString(untaggedMyTaggedString: String): MyTaggedString = {
val myTaggedString = tag[MyTaggedStringTag](untaggedMyTaggedString)
myTaggedString
}
}
implicit class MyTaggedStringOps(val myTaggedString: MyTaggedString) extends AnyVal { def untagged = myTaggedString.asInstanceOf[String] }
So, it's a lot of boilerplate per definition. I'd really like to be able to generate this by doing something like:
@tagged[String] type MyTaggedString
Is there a way to do something like this with Scala Meta, or some other code generation tool?
Updated
This is now fully working and can be seen in a new library I call Taggy. Here is the latest version of the macro:
The parsing of the macro syntax and code generation are separated for readability. You could inline
TaggedImpl.expand
into themeta
block. Also note that the syntax here is now@tagged type MyTaggedString = String
.Original answer
I got it working as a proof of concept. But it takes the string name of the underlying type: