My code looks like this:
val people = Array(Array("John", "25"), Array("Mary", "22"))
val headers = Seq("Name", "Age")
val myTable = new Table(people, headers)
I get this syntax error:
overloaded method constructor Table with alternatives:
(rows: Int,columns: Int)scala.swing.Table
<and>
(rowData: Array[Array[Any]],columnNames: Seq[_])scala.swing.Table
cannot be applied to
(Array [Array[java.lang.String]], Seq[java.lang.String])
I don't see why the second alternative isn't used. Is there a distinction between "Any" and "_" that's tripping me up here?
As Kim already said, you need to make your array covariant in his element type, because Scala's Arras are not covariant like Java's/C#'s.
This code will make it work for instance:
class Table[+T](rowData: Array[Array[T]],columnNames: Seq[_])
This just tells the compiler that T should be covariant (this is similar to Java's ? extends T or C#'s out T).
If you need more control about what types are allowed and which not, you can also use:
class Table[T <: Any](rowData: Array[Array[T]],columnNames: Seq[_])
This will tell the compiler that T can be any subtype of Any (which can be changed from Any to the class you require, like CharSequence in your example).
Both cases work the same in this scenario:
scala> val people = Array(Array("John", "25"), Array("Mary", "22"))
people: Array[Array[java.lang.String]] = Array(Array(John, 25), Array(Mary, 22))
scala> val headers = Seq("Name", "Age")
headers: Seq[java.lang.String] = List(Name, Age)
scala> val myTable = new Table(people, headers)
myTable: Table[java.lang.String] = Table#350204ce
Edit: If the class in question is not in your control, declare the type you want explicitly like this:
val people: Array[Array[Any]] = Array(Array("John", "25"), Array("Mary", "22"))
Update
This is the source code in question:
// TODO: use IndexedSeq[_ <: IndexedSeq[Any]], see ticket [#2005][1]
def this(rowData: Array[Array[Any]], columnNames: Seq[_]) = {
I wonder if someone forgot to remove the workaround, because #2005 is fixed since May 2011 ...
Array[Array[String]] is not a subtype of Array[Array[Any]] because Array's type parameter is not covariant. You should read up on co-, contra- and invariance. This should fix it:
val people =
Array(Array("John", "25"), Array("Mary", "22")).asInstanceOf[Array[Array[Any]]
Related
I've defined some Scala classes:
class Drink
class SoftDrink extends Drink
class Cola extends SoftDrink
class VendingMachine[A](val currentItem: Option[A], items: List[A]) {
def this(items: List[A]) = this(None, items)
def addAll[B >: A](newItems: List[B]): VendingMachine[B] =
new VendingMachine(items ++ newItems)
}
Then I ran the following code snippet:
val colasVM: VendingMachine[Cola] = new VendingMachine(List(new Cola, new Cola))
// It works
val softDrinksVM: VendingMachine[Drink] = colasVM.addAll(List(new SoftDrink))
// Compile Error: You may wish to define A as +A instead. (SLS 4.5)
val softDrinksVM2: VendingMachine[Drink] = new VendingMachine[SoftDrink](None, null)
In my opinion, colasVM.addAll(List(new SoftDrink)) returns VendingMachine[SoftDrink] type data, and it can't be assigned to a VendingMachine[Drink] variable since they're not the same type.
However val softDrinksVM: VendingMachine[Drink] = colasVM.addAll(List(new SoftDrink)) can be compiled successfully in my side, can anyone help explain why?
Thanks so much!
That happens because of the lower bound type, type inference and covariance.
colasVM is a VendingMachine[Cola], so its type parameter A is Cola.
Method addAll has a type parameter B that is any super type of A. If A is Cola, B can be Cola, SoftDrink, Drink, it can even be AnyRef or Any.
When you call addAll you are not telling to the compiler which type is B, so it has to infer it. If softDrinksVM2 is of type VendingMachine[Drink], B has to be Drink.
Why your code compiles? Because List is covariant, so a List[SoftDrink] is a List[Drink].
As you can see is even possible to do something like this.
val softDrinksVM1: VendingMachine[AnyRef] = colasVM.addAll(List(new Object))
val softDrinksVM2: VendingMachine[AnyRef] = colasVM.addAll(List(new SoftDrink))
Take a look to this link for more information
https://docs.scala-lang.org/tour/variances.html
I have a unit test, which test some solution. But this test code can also be applied for testing the other, very similar solution. What I want to make is code of test be generic to be applied to both solutions, like this:
describe("when table contains all correct rows") {
it("should be empty") {
def check[T](func: T => List[Row]) = {
val tableGen = new TableGenerator()
val table: Vector[Row] = tableGen.randomTable(100)
.sortWith(_.time isBefore _.time).distinct
val result: List[Row] = func(table)
assert(result.isEmpty)
}
check(Solution.solution1)
check(Solution.solution2)
}
}
where solutions have types:
solution1: IndexedSeq[Row] => List[Row]
solution2: Seq[Row] => List[Row]
how check() function has to be written to be able to do that?
And what's the best approaches to write this (might be in other way) with eliminated code duplication?
Update:
When I try to compile this code I get type mismatch error in func(table):
Error:(36, 29) type mismatch;
found : table.type (with underlying type scala.collection.immutable.Vector[com.vmalov.tinkoff.Row])
required: T
val result = func(table)
For this to work, you need to be able to pass a Vector[Row] to func, so any Vector[Row] has to be a T; that is, T is a supertype of Vector[Row]. You can tell this to the compiler by using a type parameter bound:
def check[T >: Vector[Row]](func: T => List[Row])
Alternately, by the above reasoning, a function T => List[Row] will also be a function Vector[Row] => List[Row] precisely when T is a supertype of Vector[Row], and the Scala compiler knows about this (functions are contravariant in their argument type(s)). So this signature is equivalent to simpler
def check(func: Vector[Row] => List[Row])
Of course, you can generalize this, but how much depends on your specific desires. E.g. you can replace List[Row] with Seq[Row] (everywhere), or with a type parameter and pass an extra function to check:
def check[A](func: Vector[Row] => A)(test: A => Boolean) = {
val table = ...
val result = func(table)
assert(test(result))
}
check(Solution.solution1)(_.isEmpty) // the compiler infers A is List[Row]
Your case, maybe is enough to abstract the type on a more specific way, like defining that you are expecting a Travesable.
def check[S[_] : Traversable](func: S[Row] => List[Row])
That would accept either Seq or IndexedSeq as valid parameter, while it also be limiting it.
I hope it helps
EDITED: Check Alexey Romanov Answer, as with this you will not be able to call func the way you do it. Sorry about that
def check(func: Vector[Row] => List[Row])
Consider the following example
val strings = Seq("foo", "bar")
val numbers = Seq(1,2,3)
strings.diff(numbers)
This is valid code (and results in an empty list), but why isn't scala picking up that we are comparing sets of different types?
There seems to be a type bound B >: A defined for intersect, diff and union but somehow it does not cause the compiler to reject my example as invalid.
Is there a type-strict/safe way of to do set operations in scala?
Because the Seq is covariant type(+A)
If you want to diff with stricted type, you can try it by:
strings.diff[String](numbers)
Even if I appreciate chengpohi's answer, it requires additional typing/thought, so I now use strict versions (continuing my example from the question):
implicit class StrictSetOps[T](someSeq: Seq[T]) {
def strictDiff(that: Seq[T]) = {
someSeq.diff(that)
}
def strictUnion(that: Seq[T]) = {
someSeq.union(that)
}
def strictIntersect(that: Seq[T]) = {
someSeq.intersect(that)
}
}
// rejected by compiler
strings.strictDiff(numbers)
// compiler and the lazy developer are happy
val otherStrings = Seq("foo", "bar")
strings.strictDiff(otherStrings)
Given:
val personsOpt:Option[List[Person]] = ???
I prefer:
persons = personsOpt.fold(List[Person]()){person => person}
To this:
persons = personsOpt.getOrElse(List[Person]())
For type safety reasons. For example this does not compile:
persons = personsOpt.fold(Nil){person => person}
Is there a simple way to get the type safety but not have {person => person}?
EDIT: Two things now concretely understood:
There is nothing un-type-safe about getOrElse. For instance this does not compile: personsOpt.getOrElse("")
Nil is List() and if its type can't be inferred the compiler will ask you to be explicit. So there can be no type issues with using Nil
I couldn't find the link just now, but I did (incorrectly) read that getOrElse was somehow less type safe than using fold with an Option.
There is the function identity which is defined in Predef:
persons = personsOpt.fold(List[Person]())(identity)
I find this however a lot less readable than using getOrElse, and using this does not make your code more type-safe than using getOrElse. Note that passing Nil to getOrElse will make it return the correct type:
scala> case class Person(name: String)
scala> val personsOpt:Option[List[Person]] = None
personsOpt: Option[List[Person]] = None
scala> val persons = personsOpt.getOrElse(Nil)
persons: List[Person] = List()
Note that persons is a List[Person].
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
}