I am trying to model my class hierarchy in case classes. I appreciate related discussion about duplication of case class properties here.
Consider the class hierarchy shown below.
trait Super {
def a:String
}
case class Child1(a:String, b:String) extends Super {
override def toString = s" a = $a, b= $b"
}
case class Child2(a:String, c:String) extends Super {
override def toString = s" a = $a, c= $c"
}
I have a scenario where I want to construct case class objects using basic properties like a, b, c as well as using XML. I created companion objects for these case classes as below.
object Child1 {
def apply(node: scala.xml.Node): Child1 = {
val a = (node \ "a").text
val b = (node \ "b").text
Child1(a, b)
}
}
object Child2 {
def apply(node: scala.xml.Node): Child2 = {
val a = (node \ "a").text
val c = (node \ "c").text
Child2(a, c)
}
}
In above code, I have to duplicate the line that parses value of a - (node \ "a").text. There doesn't seem to be a way to do the same even if I convert Super to an abstract superclass.
I wonder how one can do this, which I could have done very easily using abstract class and couple of constructors in Super class in Java.
UPDATE: Qualified name for scala.xml.Node type.
Indeed this is not possible with a case class. You will have to define a helper to get rid of the duplication like this.
Child1(Super.getAValue(node), c)
This is a trivial task for scala.macros or shapeless
Lets define generic xml extractor
import scala.xml.Node
trait Extract[L] extends (scala.xml.Node => L)
And it's simple implementation for string-only containing HList records:
import shapeless._
import shapeless.labelled._
implicit object extractHNil extends Extract[HNil] {
def apply(node: Node): HNil = HNil
}
implicit def extractHCons[K <: Symbol, L <: HList]
(implicit witness: Witness.Aux[K], recur: Extract[L]) =
new Extract[FieldType[K, String] :: L] {
def apply(node: Node): ::[FieldType[K, String], L] = {
val name = witness.value.name
val value = (node \ name).text
field[K](value) :: recur(node)
}
}
Now you can construct case class extractor build on top of LabelledGeneric:
implicit def extractCase[C, L]
(implicit lgen: LabelledGeneric.Aux[C, L], extract: Extract[L]) =
new Extract[C] {
def apply(node: Node): C = lgen.from(extract(node))
}
From this point you can add simple mixin for your companions:
abstract trait XmlReader[C] {
def extract: Extract[C]
def apply(node: scala.xml.Node) = extract(node)
}
And implement your builders as
object Child1 extends XmlReader[Child1] {
val extract: Extract[Child1] = implicitly
}
object Child2 extends XmlReader[Child2] {
val extract: Extract[Child2] = implicitly
}
Now you can verify it:
val node = <node>
<a>1</a>
<b>2</b>
<c>3</c>
</node>
println(Child1(node)) // a = 1, b= 2
println(Child2(node)) // a = 1, c= 3
Note that it's not very hard task to extend such parsers for work with nearly anything defined via sealed families of case classes. See picopickle as example of generic parser built with shapeless
define a method superA do it
import scala.reflect.runtime.universe._
trait Super {
def a: String
}
trait Node {
def \(s: String): String = s
}
object Node {
// also you can move it to Super companion object
implicit class SuperMethodA(val node: Node) {
def superA = node \ "a"
}
}
case class Child1(a: String, b: String) extends Super {
override def toString = s" a = $a, b= $b"
}
object Child1{
def apply(node: Node): Child1 = {
val a = node.superA //.text
val b = (node \ "b") //.text
Child1(a, b)
}
}
case class Child2(a: String, c: String) extends Super {
override def toString = s" a = $a, c= $c"
}
object Child2{
def apply(node: Node): Child2 = {
val a = node.superA //.text
val c = (node \ "c") //.text
Child2(a, c)
}
}
Related
I have an implicit class that needs to use a given parameter at runtime. So I define this implicit in another class that takes this parameter in the constructor. A simplified version of what I am doing is as follows:
case class A(p1: String) {
def foo = println("foo: " + p1)
}
class B(p2: String) {
implicit class Enhancer(a: A) {
implicit def bar = s"bar: ${a.p1}, $p2"
}
}
So when I need to use this class I then do the following:
val a = A("x")
val b = new B("y")
import b._
a.bar
I am wondering if there is a neater way than the above? Specifically the middle two lines where I define the object and then import from it. For example is there any way I could have a one line call to return the implicit class I need?
Try to add implicit parameter to Enhancer.
case class A(p1: String) {
def foo = println("foo: " + p1)
}
class B(val p2: String)
implicit class Enhancer(a: A)(implicit b: B) {
implicit def bar = s"bar: ${a.p1}, ${b.p2}"
}
val a = A("x")
implicit object b extends B("y")
a.bar
or
implicit val b = new B("y")
a.bar
Or
implicit class Enhancer(val a: A) extends AnyVal {
implicit def bar(implicit b: B) = s"bar: ${a.p1}, ${b.p2}"
}
Consider
trait E[C] {
type CONTEXT = C
def doIt(c:CONTEXT): Unit = {}
}
// My doIt method takes a C
case class ESimple[C]() extends E[C]
// ECompound's doIt method must satisfy the requirements of both
// a's and b's doIt parameters.
case class ECompound[C1,C2](a:E[C1],b:E[C2]) extends E[C1 with C2] {
override def doIt(c: CONTEXT): Unit = {
a.doIt(c)
b.doIt(c)
}
}
... and so:
case class Context
val context = Context()
val a:E[Context] = ESimple[Context]()
val b:E[Context] = ESimple[Context]()
val c:E[Context] = ECompound(a,b) // type mismatch
This fails because
val c:E[Context with Context] = ECompound(a,b) // type not mismatched
is the reported type of ECompound(a,b). So, it is possible to resolve this? ECompound(a,b).doIt really should only require a "Context", it is not simplified from "Context with Context"
I realize I can solve this by changing "... extends E[C1 with C2]" to extends[C1], but at the cost of requiring C1==C2, which I'd like to avoid.
One possible way is to define ECompound as:
case class ECompound[C1,C2, CC <: C1 with C2](a:E[C1],b:E[C2]) extends E[CC]
The drawback is that if you don't specify CC explicitly it will be inferred as Nothing, i.e.:
val c: E[Context] =
ECompound(ESimple[Context](), ESimple[Context]()) // works
val c1: E[Context with Context1] =
ECompound(ESimple[Context](), ESimple[Context1]()) // works
val c2 =
ECompound(ESimple[Context](), ESimple[Context1]())
// works, but inferred type is ECompound[Context,Context1,Nothing]
You might consider defining ECompound as:
case class ECompound[CC, C1 >: CC, C2 >: CC](a:E[C1],b:E[C2]) extends E[CC] {
override def doIt(c: CONTEXT): Unit = {
a.doIt(c)
b.doIt(c)
}
}
Well... this is embarrassing.
Turns out that I was compiling to scala 2.10. Using 2.11.8, my original worked out fine, with one small change to E:
trait E[-C] { // Added -C
def doIt(c: C): Unit = {}
def asE: E[C] = this // see below
}
case class ESimple[C]() extends E[C]
//case class ECompound[C1, C2, CC <: C1 with C2](a: E[C1], b: E[C2]) extends E[CC] {
//case class ECompound[CC, C1 >: CC, C2 >: CC](a:E[C1],b:E[C2]) extends E[CC] {
case class ECompound[C1, C2](a: E[C1], b: E[C2]) extends E[C1 with C2] {
override def doIt(c: C1 with C2): Unit = {
a.doIt(c)
b.doIt(c)
}
}
trait Context1
trait Context2
val e1: E[Context1] = ESimple[Context1]()
val e2: E[Context2] = ESimple[Context2]()
val cc11: E[Context1] = ECompound(e1, e1)
val cc12: E[Context1 with Context2] = ECompound(e1, e2)
case class X()
cc12.doIt(new X with Context1 with Context2)
However, the ugly part about this is:
def compileTimeType[T](x: T)(implicit tag: TypeTag[T]) = tag.tpe
val a = ECompound(e1, e1)
val b = ECompound(a, a)
val c = ECompound(b, b)
println( compileTimeType( c.asE ) )
gives:
com.example.E[com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1
with com.example.Context1]
which (without loss in generality), can be simplified to:
com.example.E[com.example.Context1]
but is not. Sure makes for some nasty compiler errors...
If you can avoid this mess, this answer is yours.
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)
I'm looking for a way to have classes that behave just like case classes, but that are automatically hash consed.
One way to achieve this for integer lists would be:
import scala.collection.mutable.{Map=>MutableMap}
sealed abstract class List
class Cons(val head: Int, val tail: List) extends List
case object Nil extends List
object Cons {
val cache : MutableMap[(Int,List),Cons] = MutableMap.empty
def apply(head : Int, tail : List) = cache.getOrElse((head,tail), {
val newCons = new Cons(head, tail)
cache((head,tail)) = newCons
newCons
})
def unapply(lst : List) : Option[(Int,List)] = {
if (lst != null && lst.isInstanceOf[Cons]) {
val asCons = lst.asInstanceOf[Cons]
Some((asCons.head, asCons.tail))
} else None
}
}
And, for instance, while
scala> (5 :: 4 :: scala.Nil) eq (5 :: 4 :: scala.Nil)
resN: Boolean = false
we get
scala> Cons(5, Cons(4, Nil)) eq Cons(5, Cons(4, Nil))
resN: Boolean = true
Now what I'm looking for is a generic way to achieve this (or something very similar). Ideally, I don't want to have to type much more than:
class Cons(val head : Int, val tail : List) extends List with HashConsed2[Int,List]
(or similar). Can someone come up with some type system voodoo to help me, or will I have to wait for the macro language to be available?
You can define a few InternableN[Arg1, Arg2, ..., ResultType] traits for N being the number of arguments to apply(): Internable1[A,Z], Internable2[A,B,Z], etc. These traits define the cache itself, the intern() method and the apply method we want to hijack.
We'll have to define a trait (or an abstract class) to assure your InternableN traits that there is indeed an apply method to be overriden, let's call it Applyable.
trait Applyable1[A, Z] {
def apply(a: A): Z
}
trait Internable1[A, Z] extends Applyable1[A, Z] {
private[this] val cache = WeakHashMap[(A), Z]()
private[this] def intern(args: (A))(builder: => Z) = {
cache.getOrElse(args, {
val newObj = builder
cache(args) = newObj
newObj
})
}
abstract override def apply(arg: A) = {
println("Internable1: hijacking apply")
intern(arg) { super.apply(arg) }
}
}
The companion object of your class will have to be a mixin of a concrete class implementing ApplyableN with InternableN. It would not work to have apply directly defined in your companion object.
// class with one apply arg
abstract class SomeClassCompanion extends Applyable1[Int, SomeClass] {
def apply(value: Int): SomeClass = {
println("original apply")
new SomeClass(value)
}
}
class SomeClass(val value: Int)
object SomeClass extends SomeClassCompanion with Internable1[Int, SomeClass]
One good thing about this is that the original apply need not be modified to cater for interning. It only creates instances and is only called when they need to be created.
The whole thing can (and should) also be defined for classes with more than one argument. For the two-argument case:
trait Applyable2[A, B, Z] {
def apply(a: A, b: B): Z
}
trait Internable2[A, B, Z] extends Applyable2[A, B, Z] {
private[this] val cache = WeakHashMap[(A, B), Z]()
private[this] def intern(args: (A, B))(builder: => Z) = {
cache.getOrElse(args, {
val newObj = builder
cache(args) = newObj
newObj
})
}
abstract override def apply(a: A, b: B) = {
println("Internable2: hijacking apply")
intern((a, b)) { super.apply(a, b) }
}
}
// class with two apply arg
abstract class AnotherClassCompanion extends Applyable2[String, String, AnotherClass] {
def apply(one: String, two: String): AnotherClass = {
println("original apply")
new AnotherClass(one, two)
}
}
class AnotherClass(val one: String, val two: String)
object AnotherClass extends AnotherClassCompanion with Internable2[String, String, AnotherClass]
The interaction shows that the Internables' apply method executes prior to the original apply() which gets executed only if needed.
scala> import SomeClass._
import SomeClass._
scala> SomeClass(1)
Internable1: hijacking apply
original apply
res0: SomeClass = SomeClass#2e239525
scala> import AnotherClass._
import AnotherClass._
scala> AnotherClass("earthling", "greetings")
Internable2: hijacking apply
original apply
res1: AnotherClass = AnotherClass#329b5c95
scala> AnotherClass("earthling", "greetings")
Internable2: hijacking apply
res2: AnotherClass = AnotherClass#329b5c95
I chose to use a WeakHashMap so that the interning cache does not prevent garbage collection of interned instances once they're no longer referenced elsewhere.
Code neatly available as a Github gist.
Maybe a little hacky, but you could try defining your own intern() method, like Java's String has:
import scala.collection.mutable.{Map=>MutableMap}
object HashConsed {
val cache: MutableMap[(Class[_],Int), HashConsed] = MutableMap.empty
}
trait HashConsed {
def intern(): HashConsed =
HashConsed.cache.getOrElse((getClass, hashCode), {
HashConsed.cache((getClass, hashCode)) = this
this
})
}
case class Foo(bar: Int, baz: String) extends HashConsed
val foo1 = Foo(1, "one").intern()
val foo2 = Foo(1, "one").intern()
println(foo1 == foo2) // true
println(foo1 eq foo2) // true
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)
}
}