tusharmath
tusharmath

Reputation: 10992

How to create more specific types for String and other data types while creating domain models

While domain modeling how can I ensure that two types — User and Place don't interchange their name fields, which are of type String.

trait User {
  val firstName: String
  val lastName: String
}


object User {
  final class Live(val firstName: String,val lastName: String) extends User 
  def apply(firstName: String, lastName: String): User = new Live(firstName, lastName)
}


trait Place {
  val name: String  
}


object Place {
  final class Live(val name: String) extends Place
  def apply(name: String): Place = new Live(name)
}

val a = User("Tushar", "Mathur")
val b = Place("Mumbai")


val c = Place(a.firstName) 
// How do I disable this ^

Upvotes: 1

Views: 50

Answers (1)

yǝsʞǝla
yǝsʞǝla

Reputation: 16412

This is supported in Scala as in the example below. There are some libraries that can reduce boilerplate but I'm just showing the simplest option:

// define more restrictive String-like types. AnyVal construction can be free from 
// overhead with some caveats.
case class UserName(name: String) extends AnyVal
case class PlaceName(name: String) extends AnyVal

// define your classes (I've changed them a bit for brevity):
case class User(name: UserName)
case class Place(name: PlaceName)

// implicits for convenience of construction:
implicit val strToUserName = UserName(_)
implicit val strToPlaceName = PlaceName(_)

// test it out:
scala> val u = User("user")
u: User = User(UserName(user))

scala> val p = Place("place")
p: Place = Place(PlaceName(place))

// as expected you CAN'T do this:
scala> User(p.name)
<console>:17: error: type mismatch;
 found   : PlaceName
 required: UserName
       User(p.name)
              ^

// comparison test:
scala> p.name == u.name
<console>:16: warning: comparing case class values of types PlaceName and UserName using `==' will always yield false
       p.name == u.name
              ^
res3: Boolean = false

// you can still get at the string value:
scala> p.name
res6: PlaceName = PlaceName(place)

scala> p.name.name
res5: String = place

Upvotes: 2

Related Questions