Reputation: 55
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
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
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