I am looking for a clean object-orientated way to model the following (in Scala):
A person can be:
A manager at some firm
A mathematician
A world-class tennis player
A hobbyist programmer
A volunteer at a local school
A creative painter
This suggests that we introduce a Person super-class and sub-classes:
class Manager
class Mathematician
class TennisPlayer
class HobbyistProgrammer
class Volunteer
class Painter
The Manager class has methods such as: getSalary(), workLongHours(), findNewJob(), etc. The TennisPlayer class has methods such as: getWorldRanking(), playGame(), strainAnkle(), etc. And so on. In addition there are methods in class Person such as becomeSick(). A sick manager loses his job and tennis player stops playing in the season.
Futhermore the classes are immutable. That is, for instance strainAnkle() returns a new TennisPlayer that that has a strained ankle, but where all other properties remain the same.
The question is now: How do we model the fact that a person can be both a Manager and a TennisPlayer?
It's important that the solution preserves both immutability and type-safety.
We could implement classes such as:
ManagerAndMathematician
ManagerAndTennisPlayerAndPainter
ManagerAndPainter
but this leads to a combinatorial explosion of classes.
We could also use traits (with state), but then how do we implement methods such as findNewJob(), which needs to return a new person with the same traits mixed in, but with a new state of the Manager trait. Similarly, how can we implement methods such as becomeSick()?
Question: How would you implement this in a clean OO-fashion in Scala? Remember: Immutability and type-safety are a must.
This does not look to me like an ideal case for inheritance. Maybe you're trying to force things into an inheritance pattern because it seems awkward to handle composition with immutable values. Here's one of several ways to do it.
object Example {
abstract class Person(val name: String) {
def occupation: Occupation
implicit val self = this
abstract class Occupation(implicit val practitioner: Person) {
def title: String
def advanceCareer: Person
}
class Programmer extends Occupation {
def title = "Code Monkey"
def advanceCareer = practitioner
}
class Student extends Occupation {
def title = "Undecided"
def advanceCareer = new Person(practitioner.name) {
def occupation = new Programmer
}
}
}
def main(args: Array[String]) {
val p = new Person("John Doe") { def occupation = new Student }
val q = p.occupation.advanceCareer
val r = q.occupation.advanceCareer
println(p.name + " is a " + p.occupation.title)
println(q.name + " is a " + q.occupation.title)
println(r.name + " is a " + r.occupation.title)
println("I am myself: " + (r eq r.occupation.practitioner))
}
}
Let's try it out:
scala> Example.main(Array())
John Doe is a Undecided
John Doe is a Code Monkey
John Doe is a Code Monkey
I am myself: true
So this works in a somewhat useful way.
The trick here is that you create anonymous subclasses of your person each time an occupation (which is an inner class) decides to change things up. Its job is to create a new person with the new roles intact; this is helped out by the implicit val self = this and the implicit constructor on Occupation which helpfully automatically loads the correct instance of the person.
You will probably want a list of occupations, and thus will probably want helper methods that will regenerate the list of professions. Something like
object Example {
abstract class Person(val name: String) {
def occupations: List[Occupation]
implicit val self = this
def withOccupations(others: List[Person#Occupation]) = new Person(self.name) {
def occupations = others.collect {
case p: Person#Programmer => new Programmer
case s: Person#Pirate => new Pirate
}
}
abstract class Occupation(implicit val practitioner: Person) {
def title: String
def addCareer: Person
override def toString = title
}
class Programmer extends Occupation {
def title = "Code Monkey"
def addCareer: Person = withOccupations( this :: self.occupations )
}
class Pirate extends Occupation {
def title = "Sea Monkey"
def addCareer: Person = withOccupations( this :: self.occupations )
}
}
def main(args: Array[String]) {
val p = new Person("John Doe") { def occupations = Nil }
val q = (new p.Programmer).addCareer
val r = (new q.Pirate).addCareer
println(p.name + " has jobs " + p.occupations)
println(q.name + " has jobs " + q.occupations)
println(r.name + " has jobs " + r.occupations)
println("I am myself: " + (r eq r.occupations.head.practitioner))
}
}
A clean object-oriented way of solving this does not have to be Scala-specific. One could adhere to the general object-oriented design principle of favoring composition over inheritance and use something like Strategy pattern, which is a standard way of avoiding class explosion.
I think this can be solved in a manner similar to type-safe builders.
The basic idea is to represent "state" through type parameters, and use implicits to control methods. For example:
sealed trait TBoolean
final class TTrue extends TBoolean
final class TFalse extends TBoolean
class Person[IsManager <: TBoolean, IsTennisPlayer <: TBoolean, IsSick <: TBoolean] private (val name: String) {
// Factories
def becomeSick = new Person[TFalse, IsTennisPlayer, TTrue](name)
def getBetter = new Person[IsManager, IsTennisPlayer, TFalse](name)
def getManagerJob(initialSalary: Int)(implicit restriction: IsSick =:= TFalse) = new Person[TTrue, IsTennisPlayer, IsSick](name) {
protected override val salary = initialSalary
}
def learnTennis = new Person[IsManager, TTrue, IsSick](name)
// Other methods
def playGame(implicit restriction: IsTennisPlayer =:= TTrue) { println("Playing game") }
def playSeason(implicit restriction1: IsSick =:= TFalse, restriction2: IsTennisPlayer =:= TTrue) { println("Playing season") }
def getSalary(implicit restriction: IsManager =:= TTrue) = salary
// Other stuff
protected val salary = 0
}
object Person {
def apply(name: String) = new Person[TFalse, TFalse, TFalse](name)
}
It can get very wordy, and if things get complex enough, you may need something like an HList. Here's another implementation, that separates concerns better:
class Person[IsManager <: TBoolean, IsTennisPlayer <: TBoolean, IsSick <: TBoolean] private (val name: String) {
// Factories
def becomeSick = new Person[TFalse, IsTennisPlayer, TTrue](name)
def getBetter = new Person[IsManager, IsTennisPlayer, TFalse](name)
def getManagerJob(initialSalary: Int)(implicit restriction: IsSick =:= TFalse) = new Person[TTrue, IsTennisPlayer, IsSick](name) {
protected override val salary = initialSalary
}
def learnTennis = new Person[IsManager, TTrue, IsSick](name)
// Other stuff
protected val salary = 0
}
object Person {
def apply(name: String) = new Person[TFalse, TFalse, TFalse](name)
// Helper types
type PTennisPlayer[IsSick <: TBoolean] = Person[_, TTrue, IsSick]
type PManager = Person[TTrue, _, _]
// Implicit conversions
implicit def toTennisPlayer[IsSick <: TBoolean](person: PTennisPlayer[IsSick]) = new TennisPlayer[IsSick]
implicit def toManager(person: PManager) = new Manager(person.salary)
}
class TennisPlayer[IsSick <: TBoolean] {
def playGame { println("Playing Game") }
def playSeason(implicit restriction: IsSick =:= TFalse) { println("Playing Season") }
}
class Manager(salary: Int) {
def getSalary = salary
}
To get better error messages you should use specialized versions of TBoolean (ie, HasManagerJob, PlaysTennis, etc), and the annotation implicitNotFound to go with it.
Related
TL;DR
Given a hierarchy of case classes, a tree of instances can be constructed:
How do I convert that into "something else" via appropriate builders in a type safe (and user friendly) manner (without touching or altering the respective case classes) ?
Update 2021-02-25
I could make it somehow work with
import org.scalajs.dom.console
trait Root
case class Bob(name: String, as: Seq[Root]) extends Root
case class Charles(value: Int, as: Seq[Root]) extends Root
trait Builder[T] {
// can not make T covariant, as this is obj is not in a covariant position
def build(obj: T) : String
}
object Foo {
var r: Map[Root, Builder[Root]] = Map()
def attachBuilder[T <: Root](a: T, builder: Builder[T]) : Unit = {
val e = (a, builder)
r = r + e.asInstanceOf[(Root, Builder[Root])]
}
def b(name : String, as: Root*)(implicit builderB: Builder[Bob]): Bob = {
val b = Bob(name, as)
attachBuilder(b, builderB)
b
}
def c(value: Int, as: Root*)(implicit builderC: Builder[Charles]): Charles = {
val c = Charles(value, as)
attachBuilder(c, builderC)
c
}
def build(obj: Root) : String = {
r(obj).build(obj)
}
}
object UseMe {
implicit val builderB: Builder[Bob] = new Builder[Bob] {
override def build(obj: Bob): String = {
obj.name.toString + obj.as.map(a => Foo.build(a)).mkString(" ")
}
}
implicit val builderC: Builder[Charles] = new Builder[Charles] {
override def build(obj: Charles): String = {
obj.value.toString + obj.as.map(a => Foo.build(a)).mkString(" ")
}
}
def yahoo() : Unit = {
val x = Foo.b("martin", Foo.b("b2"), Foo.c(127))
console.log("This is x: " + Foo.build(x))
}
}
Still, I am very unsatisfied. Idea, I followed: Have a map that catches the respective builder for Bob or Charles. Still,
Builder[T] can not be made covariant. This prevents Builder[Bob] to be a subtype of Builder[Root]
I do not see the proper type signature for Map, so I had to typecast.
Requirements
Hierarchy of Root, Bob, Alice is extensible (so can not be sealed)
No use of static typing (by means of Shapeless HList or similar) as I simply will not have the full types as I am doing computations to assemble the tree.
Questions
What is a better approach?
Original Post
Prelude
Sigh .... mind-bending waste of hours ....... I seriously need your help!
Scenario
Given an ADT
trait A
case class B(name: String, as: Seq[A]) extends A
case class C(value: Int, as: Seq[A]) extends A
that is expected to be extended (not sealed).
Further, assume a
trait Builder[T] {
def build(obj: T) : String
}
Furthermore, with the code below we have "the creator functions" that expect the appropriate builders to in scope.
object Foo {
def b(name : String, as: A*)(implicit builderB: Builder[B]): B = {
???
// How to link ADT instance B with builder for B in a type-safe manner?
// How to trigger builder for `as`: Seq[A] ?
}
def c(value: Int, as: A*)(implicit builderC: Builder[C]): C = {
???
// How to link ADT instance C with builder for C in a type-safe manner?
}
}
With that I want to be able, after defining appropriate builders as implicit vals for B and C to do
object UseMe {
implicit val builderB: Builder[B] = new Builder[B] {
override def build(obj: B): String = {
obj.toString
// and build the as
}
}
implicit val builderC: Builder[C] = new Builder[C] {
override def build(obj: C): String = {
obj.value.toString
// and also build the as
}
}
val x = Foo.b("martin", Foo.b("b2"), Foo.c(127))
// Questions
// How to create a string representation (that is what the builder is doing) for x
// Something like:
// build(x)
}
By intention, I removed all my misleading tries in code, also not to induce any bias.
Tries
A builder impl that uses dynamic type information (via case b: B => ...) is working, but as I expect the ADT to be extended, this is not an option.
All my tries to model by generic types have failed. (Approaches with HList (Shapeless) might be feasible but are not considered, as I think this can be solved in plain Scala)
Questions
How to define methods in Foo?
How to solve builder pattern / creational pattern best for ADTs?
Looking forward to your answers!
When I extend traits I can choose which method implementation to use. Like here:
object Main {
def main(args: Array[String]): Unit = {
val c = new C
println(c.a)
println(c.b)
}
trait Parent {
def foo: String
}
trait A extends Parent {
override def foo = "from A"
}
trait B extends Parent {
override def foo = "from B"
}
class C extends A with B {
val b = super[A].foo
val a = super[B].foo
}
}
But if I want to do the same with self-types it's seems like it's not possible:
object Main {
def main(args: Array[String]): Unit = {
val c = new C with A with B
println(c.a)
println(c.b)
}
trait Parent {
def foo: String
}
trait A extends Parent {
override def foo = "from A"
}
trait B extends Parent {
override def foo = "from B"
}
class C {
self: A with B =>
val b = super[A].foo
val a = super[B].foo
}
}
This doesn't compile. Am I right and it's not possible? If I'm right, why is that and is there a workaround for it?
UPDATE:
Why do I needed in a first place? I was playing around with dependency injection using self-types instead of constructor injection. So I had a base trait Converter and child traits FooConverter and BarConverter. And I wanted to write it like that(which doesn't work of course):
object Main {
class Foo
class Bar
trait Converter[A] {
def convert(a: A): String
}
trait FooConverter extends Converter[Foo] {
override def convert(a: Foo): String = ???
}
trait BarConverter extends Converter[Bar] {
override def convert(a: Bar): String = ???
}
class Service {
this: Converter[Foo] with Converter[Bar] =>
def fooBar(f: Foo, b:Bar) = {
convert(f)
convert(b)
}
}
}
I thought it's because of generics, but it turned that it's not. So I was just wondering if it's possible to somehow invoke super method of chosen trait with self-types. Because with simple inheritance it's possible. As for my original problem I can write it like this and it will work:
object Main {
class Foo
class Bar
trait Converter[A] {
def convert(a: A): String
}
trait FooConverter extends Converter[Foo] {
override def convert(a: Foo): String = ???
}
trait BarConverter extends Converter[Bar] {
override def convert(a: Bar): String = ???
}
class Service {
this: FooConverter with BarConverter =>
def fooBar(f: Foo, b:Bar) = {
convert(f)
convert(b)
}
}
}
Probably tighter abstraction, but I'm not sure if it's bad for this kind of situation and if I need such broad abstraction like Converter[A] at all.
Calling super methods from already constructed type is impossible (you can do it only from the inside). In your example, you're trying to call foo on the instance self, which is constructed in runtime, so foo is virtual and could be overridden - compiler doesn't know which actual implementation is going to be called (formal vs real type problem). So technically - it's impossible to do what you want (call virtual method as a static one).
The naive hack is :
trait CC extends A with B {
val b = super[A].foo
val a = super[B].foo
}
class C {
self: CC =>
}
It basically provides encapsulation you want - you might wanna redefine a and b in class C as they're not going to be available (in type C itself) till you mix C with CC.
Note that in every example you provide (including my naive solution) - resulting val c has access to foo anyway and which exact foo is going to be called depends on how do you mix A and B (A with B or B with A). So, the only encapsulation you get is that type C itself isn't going to have foo method. This means that self-type gives you kind of a way to temporary close (make private) a method in "subclass" without violating LSP - but it's not the only way (see below).
Besides all of that, cake-injection that you're trying to implement is considered impractical by some authors. You might want to have a look at Thin Cake Pattern - as a remark, I successfully used something like this in real project (in combination with constructor injection).
I would implement your converter services this way:
class Foo
class Bar
trait Converter[A] {
def convert(a: A): String
}
object FooConverter1 extends Converter[Foo] {
override def convert(a: Foo): String = ???
}
object BarConverter1 extends Converter[Bar] {
override def convert(a: Bar): String = ???
}
trait FooBarConvertService {
def fooConverter: Converter[Foo]
def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}
}
trait Converters {
def fooConverter: Converter[Foo] = FooConverter1
def barConverter: Converter[Bar] = BarConverter1
}
object App extends FooBarConvertService with Converters with ...
This allows you to change/mock converter implementation when putting it all together.
I'd also notice that Converter[Bar] is nothing else but Function1[Bar, String] or just Bar => String, so actually you don't need separate interface for that:
sealed trait FooBar //introduced it just to make types stronger, you can omit it if you prefer
class Foo extends FooBar
class Bar extends FooBar
trait FooBarConvertService {
type Converter[T <: FooBar] = T => String
def fooConverter: Converter[Foo]
def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}
}
trait FooConverterProvider {
def fooConverter: Foo => String = ???
}
trait BarConverterProvider {
def barConverter: Bar => String = ???
}
object App
extends FooBarConvertService
with FooConverterProvider
with BarConverterProvider
You can also use def fooConverter(f: Foo): String = ??? instead def fooConverter: Foo => String = ???.
Talking about encapsulation - it's more weak here as you can access transitive dependencies, so if you really need it - use private[package] modifier.
Converters module:
package converters
trait FooBarConvertService {
type Converter[T <: FooBar] = T => String
private[converters] def fooConverter: Converter[Foo]
private[converters] def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}
}
trait FooConverterProvider {
private[converters] def fooConverter: Foo => String = ???
}
trait BarConverterProvider {
private[converters] def barConverter: Bar => String = ???
}
Core module:
package client
import converters._
object App
extends FooBarConvertService
with FooConverterProvider
with BarConverterProvider
You can use objects object converters {...}; object client {...} instead of packages if you prefer.
This encapsulation is even stronger than self-type based one, as you can't access fooConverter/barConverter from the App object (in your example foo is still accessable from val c = new C with A with B):
client.App.fooBar(new Foo, new Bar) //OK
client.App.fooConverter
<console>:13: error: method fooConverter in trait FooConverterProvider cannot be accessed in object client.App
client.App.fooConverter
^
Keep in mind that self types are meant to allow you to require that any client code that uses the trait you are mixing in must also mix in another trait. In other words it is a way of declaring dependencies. But it is not classical inheritance. So when you say class C { self: A with B => } A and B actually are not there at the time. You have just defined that the client code has to mix in A and B in order to then mix in C.
But for your specific use case, it seems like you can accomplish the same goal with something like this code. In other words first create a third trait and then extend it into a specific class.
object DoubleSelfType extends App {
val c = new DoubleFoo
println(c.a)
println(c.b)
trait Parent {
def foo: String
}
trait A extends Parent {
override def foo = "from A"
}
trait B extends Parent {
override def foo = "from B"
}
trait C {
self: A with B =>
val a = ""
val b = ""
}
class DoubleFoo extends C with A with B {
override val b = super[A].foo
override val a = super[B].foo
}
}
There is the following API for Slick CRUD (Slick-2.1.0, Scala-2.11.4):
trait HasId {
type Id
def id: Option[Id]
}
trait HasIdColumn[E <: HasId] {
def id: scala.slick.lifted.Column[E#Id]
}
trait SlickExtensions {
val driver: scala.slick.driver.JdbcProfile
import driver.simple._
trait BaseDAO[T <: Table[E], E] {
val query: TableQuery[T]
}
trait HasIdActions[T <: Table[E] with HasIdColumn[E], E <: HasId]
extends BaseDAO[T, E] {
//line L1: this implicit val is needed to execute query.filter(_.id === id)
// what can be done in order to save the user from the necessity
// to override this value?
implicit val mappingId: BaseColumnType[E#Id]
def findById(id: E#Id)(implicit session: Session): Option[E] =
query.filter(_.id === id).firstOption
...
}
}
I apply this SlickExtensions as follows:
case class Entity(id: Option[Long] = None, value: String) extends HasId {
type Id = Long }
trait EntityComponent extends SlickExtensions {
import driver.simple._
class EntitiesTable(tag: Tag) extends Table[Entity](tag, "entities")
with HasIdColumn[Entity] {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def value = column[String]("value", O.NotNull)
def * = (id.?, value) <>(Entity.tupled, Entity.unapply)
}
object Entities extends HasIdActions[EntitiesTable, Entity] {
val query = TableQuery[EntitiesTable]
/* line L2: from slick library: ImplicitColumnTypes */
override implicit val mappingId = driver.simple.longColumnType
}
}
End point to execute queries:
val c = new EntityComponent {
lazy val driver = play.api.db.slick.Config.driver
}
db.withSession { implicit session =>
c.Entities.findById(1) foreach println
}
The main question is how to get rid of "implicit val mappingId" overriding in line L2?
I tried to create a class:
abstract class IdImplicits[E<:HasId](implicit val mappingId:BaseColumnType[E#Id])
and inherited it as follows:
object Entities extends IdImplicits[EntitiesTable, Entity]
with HasIdActions[EntitiesTable, Entity] {
val query = TableQuery[EntitiesTable]
//override implicit val mappingId: driver.simple.longColumnType
}
However it seems to me that such approach is redundant.
It would be great if I could hide "implicit val mappingId" inside SlickExtensions.
Here is the link to the same question
UPD:
In my project, I'd like to add HasName, HasValue[V] and some other mixins to construct the following DAOs:
object EntitiesDAO extends HasIdActions
with HasNameActions
with HasValueActions with NameToIdActions with ValueToIdActions {
...
override def nameToId(name:String):Option[E#Id]
override def valueToId(value:E#ValueType):Option[E#Id]
...
}
It leads to the following problems:
1) implicits for BaseColumnTypes, mentioned in my topic, should be taken into consideration for HasId, HasValue mixins
2) If implicits BaseColumnTypes are used as parameters of constructor of abstract classes then these classes can't be mixed in one EntityDAO object (the problem is described here).
3) If one abstract class is used for each variant of EntityDAO, then we get ugly-looking combinations, for example:
abstract class IdValueNameImplicits[E <: HasId with HasValue with HasName]
(implicit val idMapper:BaseColumnType[E#Id],
implicit val valueMapper:BaseColumnType[E#ValueType])
You can't do that because you are inside a trait and E#Id is only defined when you have a concrete implementation of it.
As you already discovered, you have to define your BaseColumnType when your trait is implemented because only then you have a defined type for E#Id.
Another option is not to have a trait but an abstract class where you can have a implicit BaseColumnType passed to the constructor.
I have a small project that does exactly what you are looking for. You can find it here: https://github.com/strongtyped/active-slick
There is also an Activator template.
http://typesafe.com/activator/template/slick-active-record
You can use it as is or as inspiration for your own.
Have fun!
Suppose I have some abstract value field defined in a trait:
trait Base {
val toBeOverride: String
}
case class Impl(other:Int) extends Base {
override val toBeOverride = "some value"
}
How can I write a function that I can easily get a cloned instance only overriding the toBeOverride value, like this:
// copy only available to case class instance
// v does not have method 'copy'
def overrideBaseValue[T <: Base](v: Base) =
v.copy(toBeOverride = "prefix" + v.toBeOverride)
?
Edit
#som-snytt, I don't think this is a duplicate, just like a Trait is not the same as an Abstract Class. And the answers of that question do not satisfy me, see below.
#Blaisorblade, yes, it is a problem. For instances of each sub case class, the toBeOverride field are the same, so it should not appear in the constructor.
For now all the suggestions are to define an customized copy method in each(!) sub case class and that in my opinion is ugly and shows the incapability of the language.
The simplest solution is to just add the method you want to Base:
trait Base {
val toBeOverride: String
def copyBase(newToBeOverridden: String): Base
}
case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
def copyBase(newToBeOverridden: String) = copy(toBeOverride = newToBeOverridden)
}
This also allows to directly create an instance of Impl while specifying the value of toBeOverride (which wasn't possible). The only disadvantage is that now pattern matches using Impl have to change syntax - please update your question and add a comment if that's a problem.
BTW, if you just want to add a prefix (as in your example), that's no problem:
case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
def copyBase(newToBeOverridden: String) = copy(toBeOverride = toBeOverride + newToBeOverridden)
}
Here are two mechanisms.
Apparently, in the near future you'll be able to write a macro that can emit the anonymous subclass, but until then, I think this typeclass is not arduous.
Just kicking the tires on Dynamic here.
import scala.language.dynamics
import scala.reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
trait Base {
def m: String
}
case class Impl(p: Int) extends Base {
override val m = "some value"
}
trait Basic extends Dynamic {
protected def m: String
def selectDynamic(f: String): Any =
if ("m" == f) m else reflecting(this, f)
protected def reflecting(b: Basic, f: String) = {
val im = cm.reflect(b)
val member = im.symbol.typeSignature member newTermName(f)
require(member != NoSymbol, s"No such member $f")
(im reflectMethod member.asMethod)()
}
}
case class Implic(p: Int) extends Basic {
override protected val m = "some value"
}
object Test extends App {
implicit class Copy[A <: Base](val b: A) {
def overriding(overm: String): A = (b match {
case impl: Impl => new Impl(impl.p) { override val m = overm }
case b: Base => new Base { override val m = overm }
}).asInstanceOf[A]
}
implicit class Proxy[A <: Basic : ClassTag](val b: A) {
def proximately(overm: String): Basic = new Basic {
override val m = overm
override def selectDynamic(f: String): Any =
if ("m" == f) overm else reflecting(b, f)
override def toString = b.toString
}
}
// asked for this
//def overriding[T <: Base](v: Base) = v.copy(m = "prefix" + v.m)
/* want something like this
def overriding[T <: Base](v: Base) = new Impl(v.p) {
override val m = "some value"
} */
val a = Impl(5)
val b = a overriding "bee good"
Console println s"$a with ${a.m} ~> $b with ${b.m}"
// or
val c = Implic(7)
val d = c proximately "dynomite"
Console println s"$c with ${c.m} ~> $d with ${d.m}"
}
Since traits don't get copy methods automatically, you can try using a Base case class instead:
case class Base(toBeOverride: String)
case class Impl(other: Int, someVal: String = "some value") extends Base(someVal)
def overrideBaseValue[T <: Base](v: Base) =
v.copy(toBeOverride = "prefix" + v.toBeOverride)
The problem that you're going to run into though, is that copy returns an instance of Base and I don't think that you can convert it back to your original Impl class. For instance, this won't compile:
def overrideBaseValue[T <: Base](v: T): T =
v.copy(toBeOverride = "prefix" + v.toBeOverride)
If I have a class C defined as
class C[A]
is there any way to create a new instance of A within C? Something like
class C[A] {
def f(): A = new A()
}
I understand that, if this were possible, you'd probably have to specify the constructor arguments somewhere, and that's fine.
If it's not possible, are there any design patterns for dealing with the sort of situation where you'd like to create a new instance of a type?
You could use a type class to abstract instantiation:
trait Makeable[T] {
def make: T
}
class C[T: Makeable] {
def f(): T = implicitly[Makeable[T]].make
}
For example,
implicit object StringIsMakeable extends Makeable[String] {
def make: String = "a string"
}
val c = new C[String]
c.f // == "a string"
When you instantiate C, you'll need to provide, explicitly or implicitly, a Makeable that will act as a factory of the appropriate type. That factory, of course, would be responsible for supplying any constructor arguments when it invokes the constructor.
Alternatively, you could use a Manifest, but be warned that this approach relies on reflection and is not type safe:
class C[T: Manifest] {
def f(): T = manifest[T].erasure.newInstance.asInstanceOf[T]
}
For completeness, you can also easily extend this approach to pass some or all of the constructor parameters in to the make method:
trait Makeable[Args, T] { def make(a: Args): T }
class C[Args, T](implicit e: Makeable[Args, T]) {
def f(a: Args): T = e.make(a)
}
// some examples
case class Person(firstName: String, lastName: String)
implicit val personFactory1 = new Makeable[(String, String), Person] {
def make(a: (String, String)): Person = Person(a._1, a._2)
}
implicit val personFactory2 = new Makeable[String, Person] {
def make(a: String): Person = Person(a, "Smith")
}
val c1 = new C[String, Person]
c1.f("Joe") // returns Person("Joe", "Smith")
val c2 = new C[(String, String), Person]
c2.f("John", "Smith") // returns Person("John", "Smith")
You can demand an implicit parameter, like so:
class A[T](implicit newT : T) {
val t = newT
}
All you need then is to have an implicit factory of the desired type in scope when you instanciate A, e.g. the following works:
implicit def newSeq[T] = Seq[T]()
val a = new A[Seq[String]]
As shown by:
scala> a.t
res22: Seq[String] = List()
The same as #Raphael's answer with a case class's apply method:
class Container[A](contained: A)
case class Person(name: String)
case class PersonContainer(person: Person) extends Container[Person](person)
implicit def _ = PersonContainer.apply _
class Creator {
def deserializeAndPackage[A, B <: Container[A]](data: Array[Byte])
(implicit containerCreator: (A => B)): B = {
val p = /* deserialize data as type of A */
containerCreator(p)
}
}