DEV Community

Discussion on: How to improve functions with toggle params?

Collapse
 
tobias_salzmann profile image
Tobias Salzmann • Edited

Great article!

In my last project, we used tagged types to further discriminate types of Strings from each other. The Implementation (in Scala) is straightforward:

trait Tagged[U]

type @@[+T, U] = T with Tagged[U]

implicit class TagWrapper[B](value: B) {
  def as[T <: B @@ _]: T = value.asInstanceOf[T]
}

We declared them with type aliases to have more human readable types. Taking your examples, that might look like this:

trait UseCacheTag
type UseCacheFlag = Boolean @@ UseCacheTag

trait DeferredTag
type DeferredFlag = Boolean @@ DeferredTag

They still can be used like values of the base type:

def getThing(useCache: UseCacheFlag, deferred: DeferredFlag) =
  if(useCache && deferred) ??? else ???

and here's how we used them with literals:

getThing(useCache = true.as[UseCacheFlag], deferred = false.as[DeferredFlag])

In case you're unfamiliar with scala, the as method is the one defined in the implicit class TagWrapper. During compile time, this gets translated into completely type safe code.

We made good experiences with tagged types, because they are very lightweight and serialize/deserialize well.
They are a good example of getting the benefit of type safety without making the code much harder to write.