Reputation: 53
My goal is to create a function that takes varargs of 2 or more objects when initializing a PriorityQueue containing said objects.
The relevant code is:
case class Topic(topic: String, usageFrequency: Long = 1)
object FreqOrdering extends Ordering[Topic] {
def compare(a: Topic, b:Topic) = -(a.usageFrequency compare b.usageFrequency)}
def initPriQu(a : Topic, b: Topic, c: Topic*): PriorityQueue[Topic] = {
return PriorityQueue(a,b,c)(FreqOrdering)}
Error in sbt (Scala 2):
[error] found : TopicTrenderInit.FreqOrdering.type
[error] required: scala.math.Ordering[Equals]
[error] Note: TopicTrenderInit.Topic <: Equals (and TopicTrenderInit.FreqOrdering.type <: scala.math.Ordering[TopicTrenderInit.Topic]), but trait Ordering is invariant in type T.
[error] You may wish to investigate a wildcard type such as_ <: Equals
. (SLS 3.2.10)
[error] return PriorityQueue(a,b,c)(FreqOrdering)
[error] ^
[error] /home/aaron-laptop/Documents/Scala/topic_trender100/src/main/scala/main.scala:48:25: type mismatch;
[error] found : scala.collection.mutable.PriorityQueue[Equals]
[error] required: scala.collection.mutable.PriorityQueue[TopicTrenderInit.Topic]
[error] Note: Equals >: TopicTrenderInit.Topic, but class PriorityQueue is invariant in type A.
[error] You may wish to investigate a wildcard type such as_ >: TopicTrenderInit.Topic
. (SLS 3.2.10)
[error] return PriorityQueue(a,b,c)(FreqOrdering)
When there is no '*' indicating a vararg everything works, no errors. I think what confuses me the worst is the required: scala.math.Ordering[Equals] error I'm seeing. I also read an article on pattern matching, but I feel i'll have to read more on it to understand implementation. What's going on here?
Thanks.
Upvotes: 0
Views: 69
Reputation: 22850
The problem is that, when you pass a, b, c
to the Factory of PriorityQueue
. What the compilers see is that you passed three arguments of type A
and the only super type between those tree is Equals
.
That is because a
& b
are Topics
, which as a case class extends Equals
, and c
is of type Seq[Topic]
(a varargs arguments is passed as a Seq
), which also extends Equals
.
And that is why it is asking for a Ordering[Equals]
.
You may fix it as follows.
(Note this is quite ugly and maybe innificient, you may consider just recieve one varargs instead of a
& b
and then c
)
// It will be good to have this as an implicit so you don't have to pass it explicitly
// every time you need to.
// And it is always preferable to have an implicit val with an explicit type signature
// than an implicit object.
implicit val TopicOrdering: Ordering[Topic] = new math.Ordering[Topic] {
override def compare(a: Topic, b:Topic): Int =
-(a.usageFrequency compare b.usageFrequency)
}
import scala.collection.mutable.PriorityQueue
def initPriQu(a: Topic, b: Topic, others: Topic*): PriorityQueue[Topic] =
// 1. Don't use return in scala.
// 2. Here I made a Seq of Seqs of Topic - Seq[Seq[Topic]]
// then I flatten it to have a Seq of Topic - Seq[Topic]
// and finally used the ':_*' operator to turn a Seq into a varargs.
PriorityQueue((Seq(a, b) ++ others): _*)
Upvotes: 1
Reputation: 27356
The problem is the way you are building the PriorityQueue
. You are passing it two values of type Topic
and one of type Seq[Topic]
so the result is PriorityQueue[Any]
.
This should work:
def initPriQu(a : Topic, b: Topic, c: Topic*): mutable.PriorityQueue[Topic] =
mutable.PriorityQueue(Seq(a, b) ++ c:_*)(FreqOrdering)
Also, don't use return
.
Upvotes: 5