views:

139

answers:

3

I wanted to compare the cardinality of two sets in Scala. Since stuff sometimes "just work" in Scala, I tried using < between the sets. It seems to go through, but I can't make any sense out of the result.

Example:

scala> Set(1,2,3) < Set(1,4)
res20: Boolean = true
  • What does it return?
  • Where can I read about this method in the API?
  • Why isn't it listed anywhere under scala.collection.immutable.Set?

Update: Even the order(??) of the elements in the sets seem to matter:

scala> Set(2,3,1) < Set(1,3)
res24: Boolean = false

scala> Set(1,2,3) < Set(1,3)
res25: Boolean = true
+1  A: 

If you want to compare the cardinality, just do so directly:

scala> Set(1, 2, 3).size < Set(2, 3, 4, 5).size
res0: Boolean = true
Randall Schulz
Sure. That doesn't answer any of the questions though.
aioobe
A: 

My knowledge of Scala is not extensive, but doing some test, I get the following:

scala> Set(1,2) <
<console>:5: error: missing arguments for method < in trait Ordered;
follow this method with `_' if you want to treat it as a partially applied function
   Set(1,2) <
            ^

That tells me that < comes from the trait Ordered. More hints:

scala> Set(1,2) < _
res4: (Iterable[Int]) => Boolean = <function>

That is, the Set is evaluated into an Iterable, because maybe there is some implicit conversion from Iterable[A] to Ordered[Iterable[A]], but I'm not sure anymore... Tests are not consistent. For example, these two might suggest a kind of lexicographical compare:

scala> Set(1,2,3) < Set(1,2,4)
res5: Boolean = true

1 is equal, 2 is equal, 3 is less than 4.

scala> Set(1,2,4) < Set(1,2,3)
res6: Boolean = false

But these ones don't:

scala> Set(2,1) < Set(2,4)
res11: Boolean = true

scala> Set(2,1) < Set(2,2)
res12: Boolean = false

I think the correct answer is that found in the Ordered trait proper: There is no implementation for < between sets more than comparing their hashCode:

It is important that the hashCode method for an instance of Ordered[A] be consistent with the compare method. However, it is not possible to provide a sensible default implementation. Therefore, if you need to be able compute the hash of an instance of Ordered[A] you must provide it yourself either when inheiriting or instantiating.

Diego Sevilla
Why does it make sense that Set inherits the Ordered trait?
aioobe
Knowing nothing about Scala myself, I am also surprised to see that you think this makes sense. A 'Set', in the mathematical sense, has no order.
pkaeding
Oops, you two are right. Thanks for pointing out! I'll edit the post. I think the correct reasoning would be that "<" is defined for Iterables by (maybe) some implicit conversion, but it is right, I'm totally lost now :)
Diego Sevilla
+4  A: 

This doesn't work with 2.8. On Scala 2.7, what happens is this:

scala.Predef.iterable2ordered(Set(1, 2, 3): Iterable[Int]) < (Set(1, 3, 2): Iterable[Int])

In other words, there's an implicit conversion defined on scala.Predef, which is "imported" for all Scala code, from an Iterable[A] to an Ordered[Iterable[A]], provided there's an implicit A => Ordered[A] available.

Given that the order of an iterable for sets is undefined, you can't really predict much about it. If you add elements to make the set size bigger than four, for instance, you'll get entirely different results.

Daniel
+1. I'm just curious... In Scala 2.8 this is simply not allowed as the order of an iterable for sets is undefined?
Diego Sevilla
@Diego I think it was dropped because ordering of collections was deemed too application-specific.
Daniel