Order[Site, Product, OrderPart[Product]] or worse
Consignment[Site, Product, OrderPart[Product], Order[Site, Product,
OrderPart[Product]]] and so on.
A long and tedious list of type parameters.
Lots of things reference the generic types. For example
Delivery[Site, Consignment[Site, Product, OrderPart[Product],
Order[Site, Product, OrderPart[Product]]]]
Now if I persist with these huge lists everywhere, it works. But it's
also completely unreadable.
So I've been trying to use types. For example
trait Problem {
type TProduct <: Product
type TOrderPart <: OrderPart[TProduct]
// etc
}
but then I eventually run into type mismatch problems as I can't seem
to figure out how to get things to work both in abstract/trait area
and when I create concrete classes. Below is a reduced example of the
code that doesn't work. It fails only on the last line - when I
actually try to do something useful. Apologies for the length of the
code, but I need enough of the bits to get to the fail point.
Thanks
Tim
object Test3 {
object BasicData {
trait BaseSite { // somewhere we go
def name: String
}
trait BaseProblem[Site <: BaseSite] {
def sites: Map[String, Site]
}
}
trait ProblemType {
import BasicData._
// with this I'm trying to eliminate huge lists of type parameters
from my types. Is there another way
type Site <: BaseSite
type Problem <: BaseProblem[Site]
}
trait ProblemGenerator extends ProblemType {
def generateProblem: Problem
}
trait Events extends ProblemType {
// Imports ProblemType so I don't need long lists of parameterised
types everywhere
trait Activity {
def finishEvent: Event
}
case class Event(
where: Site,
when: Int, // in practice will be a different
date type
next: Seq[Activity])
}
trait EventGenerator extends Events {
def generateEvents(problem: Problem) : Event // for simplicity
assume a direct graph with single root
}
object SpecificData extends ProblemType { // in practice these will
have additional data
import BasicData._
type Site = SpecificSite
type Problem = SpecificProblem
case class SpecificSite(name: String, town: String) extends
BaseSite
case class SpecificProblem(sites: Map[String, Site])
extends BaseProblem[Site]
}
class SimpleProblemGenerator extends ProblemGenerator {
import SpecificData._
type Site = SpecificSite
type Problem = SpecificProblem
def generateProblem = {
val depot = SpecificSite("depot", "London")
SpecificProblem(Map(depot.name -> depot))
}
}
class SimpleEventGenerator extends EventGenerator {
def generateEvents(problem: Problem) = {
val depot = problem.sites.get("depot").get // ok to prove point
val end = Event(depot, 12, Nil)
end
}
}
object Test {
val problemGenerator = new SimpleProblemGenerator
val eventGenerator = new SimpleEventGenerator
val events =
eventGenerator.generateEvents(problemGenerator.generateProblem) //
fails with type mismatch
}
}
------------------------
error: type mismatch;
found : Test3.SpecificData.SpecificProblem
required: Test3.Test.eventGenerator.Problem
val events =
eventGenerator.generateEvents(problemGenerator.generateProblem)
You're using path dependent types here. You need to put all the related interworking classes into the same 'location' where the type is known to be the same.
The Problem on the generator is an overridable value, so the compiler can't assume it's OK to do that cast.
If you look up the cake pattern, it could help solve this issue. All you utilities become nested in "package traits" that define the abstract types.
Your final software component is just an object that mixes in all the package traits and acts like a package.
Tim
On Dec 17, 1:03 pm, Josh Suereth <joshua.suer...@gmail.com> wrote:
> You're using path dependent types here. You need to put all the related
> interworking classes into the same 'location' where the type is known to be
> the same.
>
> The Problem on the generator is an overridable value, so the compiler can't
> assume it's OK to do that cast.
>
> If you look up the cake pattern, it could help solve this issue. All you
> utilities become nested in "package traits" that define the abstract types.
>
> Your final software component is just an object that mixes in all the
> package traits and acts like a package.
https://gist.github.com/d4968289a5aaa558a28c
Tim