Martin Zhu
Martin Zhu

Reputation: 431

How to define the type of limit value in Scala?

I need to restrict the caller of the function to only use the string "asc" or "desc", so I want to use a constant to define the type.

When I use typescript, I can do like this:

function test(order: "asc" | "desc") {
    // ...
}

Then order can only be either "asc" or "desc". So how to define order in Scala?

Upvotes: 1

Views: 172

Answers (2)

Tim
Tim

Reputation: 27356

sealed trait order
case object asc extends order
case object desc extends order

Automatic conversion

You can automatically convert String to order using an implicit conversion:

object order {
  implicit def string2order(s: String): order = s match {
    case "asc" => asc
    case "desc" => desc
  }
}

Once this is defined you can pass a String to a method that takes order and it will be automatically converted. (There will be a MatchError if an invalid value is given).

Note that using strings in this way is not recommended; just use the case objects directly for better type safety.


Note that I have preserved the case of order, asc and desc to match your question, but Scala convention is to use capital letters for class and object names (Order, Asc, Desc)

Upvotes: 3

Dominic Egger
Dominic Egger

Reputation: 1016

so sadly we don't quite yet have Union Types like this. they're slotted to be in dotty though not for singleton types as in your example afaik.

The most common way it to employ an sealed trait hierarchy like this

sealed trait Order
final case object Asc extends Order
final case object Desc extends Order

It is important that the trait is final and the case classes/object final so that the compiler can do exhaustiveness checks

val ord:Order = Asc
val ord2:Order = Desc

are the only 2 possible cases because neither the trait nor the case classes/objects can be extended any further. that means that every instance of type Order has to be either Asc or Desc

ord match {
    case Asc => ???
    case Desc => ???
}

to pattern match on an Order and then do whatever

EDIT: The "anonymous" way to do this would be through the Either[A, B] datatype though that'd also require the use of singleton types (which you can get through some libraries like shapeless) or you'd just end up with Either[String, String] which is meh.

Upvotes: 2

Related Questions