lawazoni
lawazoni

Reputation: 55

Exchange of info between class

I have to link severals objects to each other with the help of their UIDs so I come up with this first code that doesn't compile then I get this solution that I don't understand.

import java.util.UUID
def generate = UUID.randomUUID()

//DOESN'T COMPILE, cannot resolve BigBrand.id
//case class BigBrand (name : String, id : UUID = generate)
//case class Outlet(name: String, big_brand_id: UUID = BigBrand.id, id : UUID = generate)

//SOLUTION ?
object BigBrand {
  case class Id(value: UUID)
}
case class BigBrand (name : String, id : BigBrand.Id = BigBrand.Id(generate))

object Outlet {
  case class Id(value: UUID)
}
case class Outlet(name: String, big_brand_id: BigBrand.Id, id : Outlet.Id = Outlet.Id(generate))

val tutu=BigBrand("tutu")
val toto=BigBrand("toto")
println(s"BigBrand id : ${tutu.id}")
println(s"BigBrand id : ${toto.id}")
val tutu1=Outlet("tutu1",tutu.id)
val toto2=Outlet("toto2",toto.id)
println(s"Outlet id : ${tutu1.id} linked with : ${tutu1.big_brand_id}" )
println(s"Outlet id : ${toto2.id} linked with :${toto2.big_brand_id}" )

Upvotes: 0

Views: 60

Answers (2)

Tim
Tim

Reputation: 27356

This is the original code that fails:

case class BigBrand (name: String, id: UUID = generate)
case class Outlet(name: String, big_brand_id: UUID = BigBrand.id, id: UUID = generate)

The reason this fails is that (as per comments) each BigBrand has its own unique id. So when you create Outlet you must provide the id for a specific instance of BigBrand. BigBrand.id (if it existed) would be a constant for all BigBrand instances.

There are two ways of dealing with it, both of which require you to create an Outlet using Outlet(name, big_brand).

The first method is to put the BigBrand instance in the Outlet rather than just the id:

case class Outlet(name: String, big_brand: BigBrand, id: UUID = generate) {
  def big_brand_id = big_brand.id
}

The second method is to pass the BigBrand instance when creating the Outlet and extract the id from that:

case class Outlet private(name: String, big_brand_id: UUID, id: UUID)

object Outlet {
  def apply(name: String, big_brand: BigBrand): Outlet =
    Outlet(name, big_brand.id, generate)
}

The best option is probably a hybrid of the two:

class Outlet private (val name: String, big_brand: BigBrand) {
  val id = generate
  def big_brand_id = big_brand.id
}

object Outlet {
  def apply(name: String, big_brand: BigBrand): Outlet =
    new Outlet(name, big_brand)
}

This requires a BigBrand to be provided when the Outlet is created, and makes name and id and big_brand_id visible while big_brand is private.

Upvotes: 1

rysh
rysh

Reputation: 131

You can use the phantom type pattern as shown below.

import java.util.UUID
def generate = UUID.randomUUID()

case class Id[A](value: UUID)
case class BigBrand (name : String, id : Id[BigBrand])
case class Outlet(name: String, big_brand_id: Id[BigBrand], id : Id[Outlet])

val tutu=BigBrand("tutu", Id(generate))
val toto=BigBrand("toto", Id(generate))
println(s"BigBrand id : ${tutu.id}")
println(s"BigBrand id : ${toto.id}")
val tutu1=Outlet("tutu1",tutu.id, Id(generate))
val toto2=Outlet("toto2",toto.id, Id(generate))
println(s"Outlet id : ${tutu1.id} linked with : ${tutu1.big_brand_id}" )
println(s"Outlet id : ${toto2.id} linked with :${toto2.big_brand_id}" )

Here is an evidence that the type test is working.

scala> Outlet("hoge", toto2.id, toto2.big_brand_id)
                            ^
       error: type mismatch;
        found   : Id[Outlet]
        required: Id[BigBrand]
                                      ^
       error: type mismatch;
        found   : Id[BigBrand]
        required: Id[Outlet]

Upvotes: 0

Related Questions