Say I define a trait and case class that extends it:
trait A {
var list: List[Int] = List()
def add(i: Int) = list = i :: list
}
case class B(str: String) extends A
If I then create an instance of B, modify the list and make a copy of it, the copy takes the values of the list as defined in trait A:
val b = B("foo")
b.add(3)
println("B: " + b.list)
println("Copied: " + b.copy(str = "bar").list)
Output:
B: List(3)
Copied: List()
I know this is probably not good functional programming practice anyway, but is there a way I can force the copy of B to take the altered version of the list for instance b?
You can accomplish this by declaring the list in the case class, and satisfy your trait's type by declaring a method. So:
trait A {
def list: List[Int]
}
case class B(i: Int, var list: List[Int]) extends A
And then your example:
scala> val b = B(2, List(1))
b: B = B(2,List(1))
scala> b.list = List(3)
b.list: List[Int] = List(3)
scala> println("B: " + b.list)
B: List(3)
scala> println("Copied: " + b.copy(i = 4).list)
Copied: List(3)
I don't know what you're doing that requires a mutable list in your class, but I imagine that even though this satisfies your example it might not satisfy whatever problem you're working on since:
scala> val a: A = b
a: A = B(2,List(3))
scala> a.list
res2: List[Int] = List(3)
scala> a.list = List(4)
<console>:15: error: value list_= is not a member of A
a.list = List(4)
When trying to view an instance of B as an A you won't be able to assign the list type. If you were dealing with an instance of A you'd have to do something like
scala> a match {
| case itsAB: B => itsAB.list = List(4); itsAB
| case other => other
| }
res3: A = B(2,List(4))
But either way, this is how you'd do it. Either that or you can follow phongnt's advice to create a non-case class and define a copy method yourself.
In a comment you said:
I failed to mention that the trait attribute needs to be modifiable with a reference to the trait itself
But this sounds like global mutable state to me. If you really need that, and I encourage you to not to then you can use an object:
object A {
#volatile
var list = List.empty[Int]
}
But I doubt this gets at what you're expressing in your question either since there is not an individual list still per instance here. So... looking at your updated question, I can only guess that something like this is what you're trying to accomplish:
object A {
#volatile
var list = List.empty[Int]
}
trait A {
def list = A.list
def add(i: Int) = A.list = i :: A.list
}
case class B(str: String) extends A
Which lets you:
scala> val b = B("hi")
b: B = B(hi)
scala> b.add(0)
scala> b.add(1)
scala> A.list
res4: List[Int] = List(1, 0)
But again, this is global mutable state, it's not a good thing. It's not threadsafe. So if there's a way for you to figure out your problem without doing this... I'd encourage you to do so.
The copy method is generated for you by the compiler when you declare a case class and it is only parameterised with the variables you define in the case class
Hence, you can definitely have copy method do that for you by declaring the variable list in the case class e.g. case class B(i: Int, list: List[Int]). You will also need override val modifier to satisfy scalac. However, scalac doesn't allow you to override a mutable variable, so you need to change the trait too, for example
trait A {
val list: List[Int] = List(1)
}
case class B(i: Int, override val list: List[Int]) extends A
Related
Why do I get a List when I create Seq using the following code?
scala> val s = Seq[Int]()
s: Seq[Int] = List()
In fact, Seq is a trait and trait cannot be initialized. What't the magic behind the scene
Seq is a trait, List is a (default) implementation.
object Seq extends SeqFactory.Delegate[Seq](List)
// ^^^^
https://github.com/scala/scala/blob/v2.13.10/src/library/scala/collection/immutable/Seq.scala#L39
implicitly[List[Int] <:< Seq[Int]] // compiles, i.e. List[Int] is a subtype of Seq[Int]
Seq is a trait and trait cannot be initialized
Firstly, even if X is a trait you can instantiate an anonymous class extending the trait: new X {}. (By the way, List is also an abstract class.)
Secondly, Seq[Int]() is desugared into Seq.apply[Int]() and you refer to not the trait Seq but its companion object.
You called apply from the Seq companion object. The implementation of apply returned a List[Int], which is an instance of Seq[Int]
There is no magic.
There is simply some code which looks roughly like this:
object Seq:
def apply[A](elements: A*) = List(elements: _*)
In other words, Seq.apply delegates to List.apply, so when you call Seq(1, 2, 3), it delegates to List(1, 2, 3), which returns a List.
Here is an extremely simplified runnable Scastie demonstration:
enum MyList[+A]:
case MyNil
case MyCons(head: A, tail: MyList[A])
object MySeq:
def apply[A](elements: A*) =
elements.foldRight(MyList.MyNil: MyList[A]) { (x, xs) =>
MyList.MyCons(x, xs)
}
MySeq() //=> MyNil: MyList[Nothing]
MySeq(1, 2, 3) //=> MyCons(1, MyCons(2, MyCons(3, MyNil))): MyList[Int]
The real code is of course more general and abstract than this simple example. The Seq object does not have an apply method of its own. Instead, it inherits from SeqFactory.Delegate[Seq](List):
object Seq extends SeqFactory.Delegate[Seq](List) {
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
override def from[E](it: IterableOnce[E]): Seq[E] = ???
}
SeqFactory.Delegate[Seq](List)'s apply method, in turn, delegates to the apply method of the object which was passed as the delegate argument:
object SeqFactory {
class Delegate[CC[A]](delegate: SeqFactory[CC]) extends SeqFactory[CC] {
// ↑↑↑↑↑↑↑↑
override def apply[A](elems: A*): CC[A] = delegate.apply(elems: _*)
// ↑↑↑↑↑↑↑↑
}
The delegate argument, if you remember, was the List object:
object Seq extends SeqFactory.Delegate[Seq](List) {
// ↑↑↑↑
override def from[E](it: IterableOnce[E]): Seq[E] = ???
}
List doesn't have its own apply method, instead it inherits it from IterableFactory, which looks like this:
def apply[A](elems: A*): CC[A] = from(elems)
So, it just delegates to from, which is an abstract method which it implements like this:
def from[B](coll: collection.IterableOnce[B]): List[B] = Nil.prependedAll(coll)
So, from delegates to Nil.prependedAll. Nil inherits prependedAll from List, where it looks like this:
override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): List[B] = prefix match {
case xs: List[B] => xs ::: this
case _ if prefix.knownSize == 0 => this
case b: ListBuffer[B] if this.isEmpty => b.toList
case _ =>
val iter = prefix.iterator
if (iter.hasNext) {
val result = new ::[B](iter.next(), this)
var curr = result
while (iter.hasNext) {
val temp = new ::[B](iter.next(), this)
curr.next = temp
curr = temp
}
releaseFence()
result
} else {
this
}
}
In your case, where you are constructing an empty Seq, you will hit the second case:
case _ if prefix.knownSize == 0 => this
Which just returns this, which is Nil, which is an instance of List[A]. Therefore, the runtime class of Seq[Int]() is List[Int], but of course, the static type is still Seq[Int].
The most general case is the fourth case, which gets the iterator of the prefix and then loops over the iterator in a while loop. Note: this is not "the Scala way"! The Scala standard library takes some shortcuts in the interest of performance and/or platform interoperability and/or simply caused by the fact that at this particular point in the library, the high-level abstractions we are used to are not available, because it is the standard library which provides those abstractions in the first place.
The Scala way to do this would be a fold, like I did above.
So, even though the real Scala library goes through half a dozen additional layers of indirection, it is pretty much equivalent to the simplified code snippet I wrote above.
I have this code to transform List[Future[Int]] to Future[List[Int]] by using scalaz sequence.
import scalaz.concurrent.Future
val t = List(Future.now(1), Future.now(2), Future.now(3)) //List[Future[Int]]
val r = t.sequence //Future[List[Int]]
because I am using Future from scalaz, so it may have implicit resolution to do the magic for me, I just wonder if the type class is custom class not predefined one like Future, how can I define implicit resolution to achieve the same result
case class Foo(x: Int)
val t = List(Foo(1), Foo(2), Foo(3)) //List[Foo[Int]]
val r = t.sequence //Foo[List[Int]]
Many thanks in advance
You need to create an Applicative[Foo] (or a Monad[Foo]) which is in implicit scope.
What you are asking for exactly won't work, since your Foo is not universally quantified (so your expected type for r doesn't make sense as Foo[List[Int]], since Foo doesn't take a type parameter.
Lets define Foo differently:
case class Foo[A](a: A)
object Foo {
implicit val fooApplicative = new Applicative[Foo] {
override def point[A](a: => A) = Foo(a)
override def ap[A,B](fa: => Foo[A])(f: => Foo[A=>B]): Foo[B] = Foo(f.a(fa.a))
}
}
Now if we make sure this implicit is in scope, we can sequence:
scala> val t = List(Foo(1), Foo(2), Foo(3))
t: List[Foo[Int]] = List(Foo(1), Foo(2), Foo(3))
scala> t.sequence
res0: Foo[List[Int]] = Foo(List(1, 2, 3))
I have a Scala collection that contains objects of different subtypes.
abstract class Base
class A extends Base
class B extends Base
val a1 = new A()
val a2 = new A()
val b = new B()
val s = List(a1, a2, b)
I'd like to filter out all the A objects or the B objects. I can do this easily if I know the object I want to filter on at compile time.
s.filter(_.isInstanceOf[A]) // Give me all the As
s.filter(_.isInstanceOf[B]) // Give me all the Bs
Can I do it if I only know the object type to filter on at runtime? I want to write a function like this.
def filterType(xs:List[Base], t) = xs.filter(_.isInstanceOf[t])
Where t indicates whether I want objects of type A or B.
Of course I can't actually write it this way because of type erasure. Is there an idiomatic Scala way to work around this using type tags? I've been reading the Scala type tag documentation and relevant StackOverflow posts, but I can't figure it out.
This has come up a few times. Duplicate, anyone?
scala> trait Base
defined trait Base
scala> case class A(i: Int) extends Base
defined class A
scala> case class B(i: Int) extends Base
defined class B
scala> val vs = List(A(1), B(2), A(3))
vs: List[Product with Serializable with Base] = List(A(1), B(2), A(3))
scala> def f[T: reflect.ClassTag](vs: List[Base]) = vs collect { case x: T => x }
f: [T](vs: List[Base])(implicit evidence$1: scala.reflect.ClassTag[T])List[T]
scala> f[A](vs)
res0: List[A] = List(A(1), A(3))
Type erasure will destroy any information in type parameters, but objects still know what class they belong to. Because of this, we cannot filter on arbitrary types, but we can filter by class or interface/trait. ClassTag is preferable to TypeTag here.
import scala.reflect.ClassTag
def filterType[T: ClassTag](xs: List[Base]) = xs.collect {
case x: T => x
}
Which we can use like:
scala> filterType[B](s)
res29: List[B] = List(B#42096939)
scala> filterType[Base](s)
res30: List[Base] = List(A#8dbc09c, A#625f8cc7, B#42096939)
This method is safe at run-time if type T is not generic. If there was a class C[T] extends Base we could not safely filter on C[String].
vars in a scala class automatically get getters & setters you can see through scala reflection via members
import scala.reflect.runtime.{universe => ru}
class A(var x: Int)
scala> ru.typeOf[A].members.filter{_.name.toString.contains("x")}
res22: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(variable x, method x_=, method x)
However, if you create a subclass, which re-uses the var name in the constructor, the getter is gone:
class B(x:Int, var y: Int) extends A(x)
scala> ru.typeOf[B].members.filter{_.name.toString.contains("x")}
res23: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(value x, method x_=)
scala> res23.head.asTerm.isVal
res25: Boolean = true
This seems a little misleading ... after all, B still does have a getter for x (and its not a val)
scala> val b = new B(5,6)
b: B = B#270288ed
scala> b.x
res26: Int = 5
scala> b.x = 7
b.x: Int = 7
scala> b.x
res27: Int = 7
If I try to pretend that the value x I got from members is a getter, I get an error:
scala> val xGetter = res23.head.asTerm
xGetter: reflect.runtime.universe.TermSymbol = value x
scala> val objMirror = ru.runtimeMirror(getClass.getClassLoader).reflect(b)
objMirror: reflect.runtime.universe.InstanceMirror = instance mirror for B#270288ed
scala> val getterMirror = objMirror.reflectField(xGetter)
scala.ScalaReflectionException: Scala field x isn't represented as a Java field, neither it has a Java accessor method
note that private parameters of class constructors don't get mapped onto fields and/or accessors,
unless they are used outside of their declaring constructors.
What is the right workaround here? Is it completely wrong to have a subclass name its constructor args the same as the names in the parent args? Or instead of calling members, do I need to work my up all super-classes to get all getters & setters?
Note that members gives me the inherited getter as long as the subclass doesn't create a constructor w/ the same name:
class Y(var x: Int)
class Z(q:Int, z: Int) extends Y(q)
scala> ru.typeOf[Z].members.filter{_.name.toString.contains("x")}
res28: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method x_=, method x)
EDIT
In case its unclear, I'm really asking:
1) is this a bug in scala reflection?
2) if not, should I:
(a) never have classes use names of constructor fields be the same as the name of fields in base classes? (if so, I'm probably defining all my classes wrong ...)
or
(b) to get all getters & setters, should I just go through the list of all parent classes and use declarations, rather than relying on members to do the right thing, since it doesn't work in this one case?
EDIT 2
in response to #som-snytt's answer, the visible methods of x are really on x in A, not the param in the constructor to B. Eg.:
class A(var x: Int){def showMeX {println(x)}}
class B(x:Int, var y: Int) extends A(x)
scala> val b = new B(5,10)
scala> b.showMeX
5
scala> b.x = 17
b.x: Int = 17
scala> b.showMeX
17
so I don't really think that the either the getter or setter for x has been shadowed, from the perspective of normal user code. Its only been shadowed for reflection code ... and it doesn't make sense to me that there would be two different versions of shadowing.
2) if not, should I: (a) never have classes use names of constructor fields be the same as the name of fields in base classes?
Since they wouldn't let me fix this, that's exactly what I do. I try to give all constructor parameters new names distinct from all inherited names. Here's a typical example within the compiler.
class PackageClassSymbol protected[Symbols] (owner0: Symbol, pos0: Position, name0: TypeName)
Yes, it's ridiculous.
https://groups.google.com/forum/#!topic/scala-language/9jLsT_RRQR0
https://issues.scala-lang.org/browse/SI-3194
https://issues.scala-lang.org/browse/SI-4762
https://issues.scala-lang.org/browse/SI-6880
Oh boy, don't keep pulling that thread...
https://issues.scala-lang.org/browse/SI-7475
https://issues.scala-lang.org/browse/SI-2568
https://issues.scala-lang.org/browse/SI-6794
It shouldn't be hard to see that the odds of any of it being addressed are nil. It's a perfect example of why I quit.
By the way, if you use -Xlint it warns you about this. That's mentioned in SI-4762.
% cat a.scala
class A(var x: Int)
class B(x:Int, var y: Int) extends A(x) {
def z = x
}
% scalac -Xlint a.scala
a.scala:3: warning: private[this] value x in class B shadows mutable x inherited from class A.
Changes to x will not be visible within class B - you may want to give them distinct names.
def z = x
^
one warning found
Well, in:
class B(x:Int, var y: Int) extends A(x)
The x in B is private (not a case class, no val or var specifier), the x in A is public (you specified var). I'm not too familiar with this reflection API, but does it show private members?
If you instead:
scala> class B(val x:Int, var y: Int) extends A(10)
<console>:9: error: overriding variable x in class A of type Int;
value x needs `override' modifier
class B(val x:Int, var y: Int) extends A(10)
^
The only public x is the one in A, which can be shown here:
scala> class B(x:Int, var y: Int) extends A(10)
defined class B
scala> new B(2,3).x
res4: Int = 10
If you want to override the parent member, use override, and change the parent to something that can be overriden.
I guess as long as the answer to my question is not (2a), then if anybody else runs into this, here is a workaround. Maybe it will be unnecessary in the future depending on the answer to (1).
(Some extra stuff here, but maybe useful also)
import scala.reflect.runtime.{universe => ru}
object ReflectionUtils {
def extractGetterSetterPairs(typ: ru.Type): Seq[GetterSetterPair] = {
typ.baseClasses.foldLeft(Seq[GetterSetterPair]()){case (acc, clsSymb) =>
extractGetterSetterPairs(clsSymb.asClass.toType, acc)
}
}
private def extractGetterSetterPairs(typ: ru.Type, acc: Seq[GetterSetterPair]): Seq[GetterSetterPair] = {
val terms = typ.declarations.collect{case x if x.isTerm => x.asTerm}
acc ++ terms.filter{x => x.isGetter}.map{x => x -> x.setter}.
filter{case(g,s) => s.isTerm}.map{case(g,s) =>
GetterSetterPair(g,s.asTerm)
}
}
def termName(t: ru.TermSymbol): String = {
t.name.toString.trim
}
}
case class GetterSetterPair(getter: ru.TermSymbol, setter: ru.TermSymbol) {
val name = ReflectionUtils.termName(getter)
val fieldType = {
//this is way more complicated than it should be. But
// 1) getters for some reason are not instances of ru.MethodType
// java.lang.ClassCastException: scala.reflect.internal.Types$NullaryMethodType cannot be cast to scala.reflect.api.Types$MethodTypeApi
// 2) its a headache to get the types out of setters
val m = setter.typeSignature.
asInstanceOf[ru.MethodType]
m.params.head.typeSignature
}
}
I've seen some blogs on the Pimp my Library pattern, and these seem to work well for adding behavior to classes.
But what if I have a case class and I want to add data members to it? As a case class I can't extend it (inheriting from a case class is deprecated/strongly discouraged). Will any of these pimp patterns allow me to add data to a case class?
No - I don't see how you could make this work because the enriched instance is usually thrown away (note: newly the pimp-my-library pattern is called enrich-my-library). For example:
scala> case class X(i: Int, s: String)
defined class X
scala> implicit class Y(x: X) {
| var f: Float = 0F
| }
defined class Y
scala> X(1, "a")
res17: X = X(1,a)
scala> res17.f = 5F
res17.f: Float = 0.0
scala> res17.f
res18: Float = 0.0
You would have to make sure you kept hold of the wrapped instance:
scala> res17: Y
res19: Y = Y#4c2d27de
scala> res19.f = 4
res19.f: Float = 4.0
scala> res19.f
res20: Float = 4.0
However, I find this not useful in practice. You have a wrapper; you're better off making this explicit
This is not the way to do. Just a proof of possibility. With this way you can get plenty of problems.
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class A(i: Int)
class B(a: A){
var s: String = ""
}
object B{
val as = scala.collection.mutable.WeakHashMap[A, B]()
}
implicit def a2b(a: A) = B.as.getOrElseUpdate(a, new B(a))
// Exiting paste mode, now interpreting.
defined class A
defined class B
defined module B
a2b: (a: A)B
scala> val a = A(1)
a: A = A(1)
scala> a.s = "test"
scala> a.s
res0: String = test
WeakHashMap: A hash map with references to entries which are weakly reachable. Entries are removed from this map when the key is no longer (strongly) referenced. This class wraps java.util.WeakHashMap.
Note that due to case class's overridden equals method you get this funny behavior:
scala> A(2).s = "test2"
scala> A(2).s
res2: String = test2
so you should not use case class or use it with override def equals(that: Any) = this eq that.asInstanceOf[AnyRef].