-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Description
Opaque types are very helpful to enforce type safety, but in practice it often leads to a silly boilerplate code when defining type-classes for them (e.g. circe codecs, db read/write, config readers, etc) which are nothing but a pass-through to a TC instance for underlying type.
One-for-all tricks like the below may help but don't cover all the cases (some derivations may diverge) and may also silently bring an implementation when pass-through is not desired
abstract class OpaqueCompanion[O, A](using ev: A =:= O):
given typeClass[TC[_]](using tc: TC[A]): TC[O] = ev.liftCo(tc)
opaque type Counter = Int
object Counter extends OpaqueCompanion[Counter, Int]
Explicitly putting given into a companion disables a way to summon TC for underlying type resulting in infinite loop in function body, e.g:
opaque type Counter = Int
object Counter:
given Numeric[Counter] = Numeric[Int] // no way, infinite loop in function
It would be much better if there's a way to declare a pass-through type-classes, something like
opaque type Counter = Int derives Numericor
opaque type Counter = Int opaque NumericMetadata
Metadata
Assignees
Labels
No labels