Reputation: 3598
I am trying to write code to wrap a modeling library. A very simplified version of the model looks like this:
class Model() {
class Thing(val name: String) {
private[Model] val foo = name + " foo "
def join(other: Thing) = new Thing(foo + other.foo)
}
def thing(name: String) = new Thing(name)
}
foo
is actually some data structure that is tied to the specific instance of the Model
. Using a Thing
from two different Model
s does not make sense, and I think this syntax prevents that.
I have several scala tests call model.thing
and use them, which works as desired.
I then started to write an abstraction layer on top of this:
class Widget(name: String)(implicit val model: Model) {
val thing = model.thing(name)
}
class CompoundWidget(name: String, children: Seq[Widget])(implicit val model: Model) extends Widget(name)
{
val combo =
children.sliding(2).foreach(pair => pair(0).thing join pair(1).thing)
}
This fails to compile:
Simple.scala:20: error: type mismatch;
found : (some other)_1.type(in value $anonfun)#model.Thing where type (some other)_1.type(in value $anonfun) <: com.proteus.orchestration.mediatorModule.scheduling.Widget with Singleton
required: _1.type(in value $anonfun)#model.Thing where type _1.type(in value $anonfun) <: com.proteus.orchestration.mediatorModule.scheduling.Widget with Singleton
children.sliding(2).foreach(pair => pair(0).thing join pair(1).thing)
^
This appears to be my attempt to prevent mixing models working too well. The compiler does not know that the Seq[Widget]
I am passing in uses the same Model
for each element, so it is giving an error.
Is there a way around this? The thing that seems likely to work (but I have not tried) is to make a class to hold the entire abstraction layer, so then the compiler can see that I am always using the same instance of Model
. However, that means that, regardless of how large it grows, I would need to keep all of the code in a single file, which will eventually become unwieldy.
My background is a Java programmer starting to use Scala, so I may just need to have the Scala Way (tm) explained to me.
Upvotes: 2
Views: 59
Reputation: 8584
What you're playing with here are dependent types. One way to do this is to make sure that both Widget
and CompoundWidget
refer to the same Model
by putting it in a shared scope:
class View(val model: Model) {
class Widget(name: String) {
val thing = model.thing(name)
}
class CompoundWidget(name: String, children: Seq[Widget]) extends Widget(name) {
val combo =
children.sliding(2).foreach(pair => pair(0).thing join pair(1).thing)
}
}
I call it View
because I assume you're going for something like MVC. I suppose the reason you're using implicits is to reduce boilerplate. You can achieve something similar here:
val view = new View(new Model)
import view._
new Widget("foo") // No need to specify View or Model
Upvotes: 3