See this implementation follows the upper bound example http://docs.scala-lang.org/tutorials/tour/upper-type-bounds.html
class Fruit(name: String)
class Apple (name: String) extends Fruit(name)
class Orange(name: String) extends Fruit(name)
class BigOrange(name:String) extends Orange(name)
class BigFLOrange(name:String) extends BigOrange(name)
// Straight from the doc
trait Node[+B ] {
def prepend[U >: B ](elem: U)
}
case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
def prepend[U >:B ](elem: U) = ListNode[U](elem, this)
def head: B = h
def tail = t
}
case class Nil[+B ]() extends Node[B] {
def prepend[U >: B ](elem: U) = ListNode[U](elem, this)
}
But this definition seems to allow multiple unrelated things in the same container
val f = new Fruit("fruit")
val a = new Apple("apple")
val o = new Orange("orange")
val bo = new BigOrange("big orange")
val foo :ListNode[BigOrange] = ListNode[BigOrange](bo, Nil())
foo.prepend(a) // add an apple to BigOrangeList
foo.prepend(o) // add an orange to BigOrangeList
val foo2 : ListNode[Orange] = foo // and still get to assign to OrangeList
So I am not sure this is a great example in the docs. And, question, how doe I modify the constraints so that..this behaves more like a List?
User #gábor-bakos points out that I am confusing invariance with covariance. So I tried the mutable list buffer. It does not later allow apple to be inserted into an Orange list Buffer, but it is not covariant
val ll : ListBuffer[BigOrange]= ListBuffer(bo)
ll += bo //good
ll += a // not allowed
So..can my example above (ListNode) be modified so that
1. it is covariant (it already is)
2 It is mutable, but mutable like the ListBuffer example (will not later allow apples to be inserted into BigOrange list
A mutable list cannot/should not be covariant in its argument type.
Exactly because of the reason you noted.
Suppose, you could have a MutableList[Orange], that was a subclass of a MutableList[Fruit]. Now, there is nothing that would prevent you from making a function:
def putApple(fruits: MutableList[Fruit], idx: Int) =
fruits(idx) = new Apple
You can add Apple to the list of Fruits, because Apple is a Fruit, nothing wrong with this.
But once you have a function like that, there is no reason you can't call it like this:
val oranges = new MutableList[Orange](new Orange, new Orange)
putApple(oranges, 0)
This will compile, since MutableList[Orange] is a subclass of MutableList[Fruit]. But now:
val firstOrange: Orange = oranges(0)
will crash, because the first element of oranges is actually an Apple.
For this reason, mutable collections have to be invariant in the element type (to answer the question you asked in the comments, to make the list invariant remove the + before B, and also get rid of the type parameter in prepend. It should just be def pretend(elem: B)).
How to get around it? The best solution is to simply not use mutable collections. You should not need them in 99% or real life scala code. If you think you need one, there is a 99% you are doing something wrong.
The major thing that you are probably missing is that prepend does not modify a list. In the line val foo2 : ListNode[Orange] = foo the list foo is still of type ListNode[BigOrange] and given covariance of parameters this assignment is valid (and there is nothing particularly awkward about it). Compiler will prevent you from assigning Fruits to Oranges (in this case assigning an Apple to an Orange is hazardous) but you have to save modified lists beforehand:
val foo: ListNode[Fruit] = ListNode[BigOrange](bo, Nil()).prepend(a).prepend(o)
val foo2: ListNode[Orange] = foo // this is not valid
Moreover your Node definition lacks return type for prepend - thus compiler infers wrong return type (Unit instead of ListNode[U]).
Here's fixed version:
trait Node[+B] {
def prepend[U >: B ](elem: U): Node[U]
}
Related
On a recent worksheet I was presented with the question asking what would be the output of the following code:
class A { def m(x:Double) = x+x }
class B[Any] extends A{ def m(x: Any) = print(x) }
class C[Any] { def m (x:Double) = x+x; def m (x: Any) = print(x) }
val obj1 = new B[Int]; val obj2 = new C[Any]
obj1.m(1); obj1.m(2.3); obj2.m(4); obj2.m(5.6)
I'm quite confused as to what having a concrete type in the square brackets after the class name would mean (i.e. class B[Any]). Is the later expression val obj1 = new B[Int] valid because Int <: Any, Int being a subclass of Any?
When later running the code snippet, the result given was simply "1" being printed. This was not what I had expected the call to obj.m(2.3) to resolve at def m(x: any), where it seems in actuality the compiler went up to A and called the m in class A.
The later expressions, obj2.m(4) and obj2.m(5.6) seems to make sense as both 4 and 5.6 would land in the function with def m(x: Double), thus not print anything out.
In what order exactly does the compiler traverse to find what to call? I'd be very grateful if someone could clear up my confusions with how polymorphism is handled here by Scala, thank you very much :)
When you do class B[Any], you define a class with a type parameter called Any. Don't confuse the type parameter name with the actual class Any. You are just shadowing its name.
You could just as fine do this:
class B[Int]
val obj = new B[String]
You may see why it is bad practice to name type parameters after actual types. Usually, people use single letter names for their type parameters, like this:
class B[T] // I just changed the name of the type parameter from "Int" to "T".
val obj = new B[String]
From what I have understood, scala treats val definitions as values.
So, any instance of a case class with same parameters should be equal.
But,
case class A(a: Int) {
lazy val k = {
println("k")
1
}
val a1 = A(5)
println(a1.k)
Output:
k
res1: Int = 1
println(a1.k)
Output:
res2: Int = 1
val a2 = A(5)
println(a1.k)
Output:
k
res3: Int = 1
I was expecting that for println(a2.k), it should not print k.
Since this is not the required behavior, how should I implement this so that for all instances of a case class with same parameters, it should only execute a lazy val definition only once. Do I need some memoization technique or Scala can handle this on its own?
I am very new to Scala and functional programming so please excuse me if you find the question trivial.
Assuming you're not overriding equals or doing something ill-advised like making the constructor args vars, it is the case that two case class instantiations with same constructor arguments will be equal. However, this does not mean that two case class instantiations with same constructor arguments will point to the same object in memory:
case class A(a: Int)
A(5) == A(5) // true, same as `A(5).equals(A(5))`
A(5) eq A(5) // false
If you want the constructor to always return the same object in memory, then you'll need to handle this yourself. Maybe use some sort of factory:
case class A private (a: Int) {
lazy val k = {
println("k")
1
}
}
object A {
private[this] val cache = collection.mutable.Map[Int, A]()
def build(a: Int) = {
cache.getOrElseUpdate(a, A(a))
}
}
val x = A.build(5)
x.k // prints k
val y = A.build(5)
y.k // doesn't print anything
x == y // true
x eq y // true
If, instead, you don't care about the constructor returning the same object, but you just care about the re-evaluation of k, you can just cache that part:
case class A(a: Int) {
lazy val k = A.kCache.getOrElseUpdate(a, {
println("k")
1
})
}
object A {
private[A] val kCache = collection.mutable.Map[Int, Int]()
}
A(5).k // prints k
A(5).k // doesn't print anything
The trivial answer is "this is what the language does according to the spec". That's the correct, but not very satisfying answer. It's more interesting why it does this.
It might be clearer that it has to do this with a different example:
case class A[B](b: B) {
lazy val k = {
println(b)
1
}
}
When you're constructing two A's, you can't know whether they are equal, because you haven't defined what it means for them to be equal (or what it means for B's to be equal). And you can't statically intitialize k either, as it depends on the passed in B.
If this has to print twice, it would be entirely intuitive if that would only be the case if k depends on b, but not if it doesn't depend on b.
When you ask
how should I implement this so that for all instances of a case class with same parameters, it should only execute a lazy val definition only once
that's a trickier question than it sounds. You make "the same parameters" sound like something that can be known at compile time without further information. It's not, you can only know it at runtime.
And if you only know that at runtime, that means you have to keep all past uses of the instance A[B] alive. This is a built in memory leak - no wonder Scala has no built-in way to do this.
If you really want this - and think long and hard about the memory leak - construct a Map[B, A[B]], and try to get a cached instance from that map, and if it doesn't exist, construct one and put it in the map.
I believe case classes only consider the arguments to their constructor (not any auxiliary constructor) to be part of their equality concept. Consider when you use a case class in a match statement, unapply only gives you access (by default) to the constructor parameters.
Consider anything in the body of case classes as "extra" or "side effect" stuffs. I consider it a good tactic to make case classes as near-empty as possible and put any custom logic in a companion object. Eg:
case class Foo(a:Int)
object Foo {
def apply(s: String) = Foo(s.toInt)
}
In addition to dhg answer, I should say, I'm not aware of functional language that does full constructor memoizing by default. You should understand that such memoizing means that all constructed instances should stick in memory, which is not always desirable.
Manual caching is not that hard, consider this simple code
import scala.collection.mutable
class Doubler private(a: Int) {
lazy val double = {
println("calculated")
a * 2
}
}
object Doubler{
val cache = mutable.WeakHashMap.empty[Int, Doubler]
def apply(a: Int): Doubler = cache.getOrElseUpdate(a, new Doubler(a))
}
Doubler(1).double //calculated
Doubler(5).double //calculated
Doubler(1).double //most probably not calculated
I want to be able to create a class/trait that behaves somewhat like an enumeration (HEnum in the first snippet below). I can't use a plain enumeration because each enum value could have a different type (though the container class will be the same): Key[A]. I'd like to be able to construct the enum roughly like this:
class Key[A](val name: String)
object A extends HEnum {
val a = new Key[String]("a")
val b = new Key[Int]("b")
val c = new Key[Float]("c")
}
And then I'd like to be able to perform more or less basic HList operations like:
A.find[String] // returns the first element with type Key[String]
A.find("b") // returns the first element with name "b", type should (hopefully) be Key[Int]
So far I've been playing with an HList as the underlying data structure, but constructing one with the proper type has proven difficult. My most successful attempt looks like this:
class Key[A](val name: String)
object Key {
def apply[A, L <: HList](name: String, l: L): (Key[A], Key[A] :: L) = {
val key = new Key[A](name)
(key, key :: l)
}
}
object A {
val (a, akeys) = Key[String, HNil]("a", HNil)
val (b, bkeys) = Key[Int, Key[String] :: HList]("b", akeys)
val (c, ckeys) = Key[Float, Key[Int] :: HList]("c", bkeys)
val values = ckeys // use this for lookups, etc
def find[A]: Key[A] = values.select[A]
def find[A](name: String): Key[A] = ...
}
The problem here is that the interface is clunky. Adding a new value anywhere besides the end of the list of values is error prone and no matter what, you have to manually update values any time a new value is introduced. My solution without HList involved a List[Key[_]] and error prone/unsafe casting to the proper type when needed.
EDIT
I should also mention that the enum example found here is not particularly helpful to me (although, if that can be adapted, then great). The added compiler checks for exhaustive pattern matches are nice (and I would ultimately want that) but this enum still only allows a homogeneous collection of enum values.
I have started working on scala now. And come to a point where I want to use Inheritance correctly.
I am stuck at once place. I have tried to read docs and other information online. but I seems like I am stuck.
Please look at this and tell me if you have faced this in the past and whether I am doing something really really wrong.
So, this is my method:
def getFacethierarchy): ListBuffer[BaseClass] = {
val obj: Childclass = new ChildClass(1, "2")
val list: ListBuffer[ChildClass] = ListBuffer[ChildClass]()
list += obj
list
}
class BaseClass(var id: Int){
}
class ChildClass(id: Int, var name: String) extends BaseClass(id){
}
Now scala Is not allowing me to return a ChildClass instance.
In Java, this would work (Child is a type of Parent)
I tried to change my method signature to return "Any".
I am not sure what I am going wrong with.
Please help, if possible.
update:
To be more specific to what I am doing, I have updated the code snippet.
ListBuffer[ChildClass] is not a subtype of ListBuffer[BaseClass] because ListBuffer being a mutable data structure, it would break the type-safety.
You want to avoid something like:
val l : ListBuffer[Int] = ListBuffer[Int](1, 2, 3)
val l2 :ListBuffer[Any] = l
l2(0) = 2.54
What you can do is to simply create a ListBuffer[BaseClass]:
def getFacethierarchy): ListBuffer[BaseClass] = {
val obj: Chlidclass = new ChildClass(1, "2")
ListBuffer[BaseClass](obj)
}
The problem stems from the fact that ListBuffer is invariant, not covariant (no + before T). It cannot be covariant. For this reason, the ListBuffer[ChildClass] is not a subtype of ListBuffer[BaseClass], even if ChildClass is a subtype of BaseClass.
You can use existential types (: ListBuffer[T] forSome {type T <: BaseClass} (hope I used the correct syntax)), or provide an additional type parameter to the method you want to use (yourMethod[T <: BaseClass]: ListBuffer[T]). If you want "MyTypes" (might be, hard to tell without further details): Scala do not support it.
Taking a closer look at your code, you might prefer to return a List[BaseClass] instead, which is covariant, so you could write:
def getFacethierarchy: List[BaseClass] = {
val obj: Chlidclass = new ChildClass(1, "2")
val list: ListBuffer[ChildClass] = ListBuffer[ChildClass]()
list += obj
list.toList
}
Trying to figure out out how to overload parenthesis on a class.
I have this code:
class App(values: Map[String,String])
{
// do stuff
}
I would like to be able to access the values Map this way:
var a = new App(Map("1" -> "2"))
a("1") // same as a.values("1")
Is this possible?
You need to define an apply method.
class App(values: Map[String,String]) {
def apply(x:String) = values(x)
// ...
}
For completeness, it should be said that your "apply" can take multiple values, and that "update" works as the dual of "apply", allowing "parentheses overloading" on the left-hand-side of assignments
Class PairMap[A, B, C]{
val contents: mutable.Map[(A,B), C] = new mutable.Map[(A, B), C]();
def apply(a:A, b:B):C = contents.get((a, b))
def update(a:A, b:B, c:C):Unit = contents.put((a, b), c)
}
val foo = new PairMap[String, Int, Int]()
foo("bar", 42) = 6
println(foo("bar", 42)) // prints 6
The primary value of all this is that it keeps people from suggesting extra syntax for things that had to be special-cased in earlier C-family languages (e.g. array element assignment and fetch). It's also handy for factory methods on companion objects. Other than that, care should be taken, as it's one of those things that can easily make your code too compact to actually be readable.
As others have already noted, you want to overload apply:
class App(values: Map[String,String]) {
def apply(s: String) = values(s)
}
While you're at it, you might want to overload the companion object apply also:
object App {
def apply(m: Map[String,String]) = new App(m)
}
Then you can:
scala> App(Map("1" -> "2")) // Didn't need to call new!
res0: App = App#5c66b06b
scala> res0("1")
res1: String = 2
though whether this is a benefit or a confusion will depend on what you're trying to do.
I think it works using apply : How does Scala's apply() method magic work?