Scala changed set: strange behavior

I cannot explain this behavior of Scala sets.

Let's start with a few definitions.

import scala.collection.mutable.Set
case class Item(name: String, content: Set[Int])
val items: Set[Item] = Set.empty

      

I will add an item to my set.

items += Item("name", Set(1, 2, 3))

      

I will release my inner kit.

items.filter(_.name == "name") foreach (_.content -= 1)
items
// res7: scala.collection.mutable.Set[Item] = Set(Item(name,Set(2, 3)))

      

So far so good.

items.filter(_.name == "name") foreach (_.content -= 2)
items.filter(_.name == "name") foreach (_.content -= 3)
items
// res12: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))

      

Perfect! Now what I REALLY want to do is delete records with an empty inner set.

items.retain(_.content.nonEmpty)
items
// res12: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))

      

Does not work. I may have done the opposite test.

items.retain(_.content.isEmpty)
items
// res14: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))

      

Does not work. The filter may not be working.

items.filter(_.content.nonEmpty)
// res15: scala.collection.mutable.Set[Item] = Set()

      

The filter is working properly. Maybe I cannot change it because it is val.

items += Item("name", Set.empty)
items
// res17: scala.collection.mutable.Set[Item] = Set(Item(name,Set()), Item(name,Set()))

      

I CAN change it. And add ... more of the same? Perhaps they are all different.

items += Item("name", Set.empty)
items
// res19: scala.collection.mutable.Set[Item] = Set(Item(name,Set()), Item(name,Set()))

      

They are not all different. Can I remove any of them?

items -= Item("name", Set.empty)
items
// res21: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))

      

I can delete ONE. Can I delete another one that I tried to delete from the beginning?

items -= Item("name", Set.empty)
items
// res23: scala.collection.mutable.Set[Item] = Set(Item(name,Set()))

      

Nope. What's happening? I am very confused.

EDIT, SOLUTION:

Using this Stackoverflow post, Scala: Ignore case class field for equals / hascode? , I solved it by changing the way the case class was declared:

case class Item(name: String)(val content: Set[Int])

      

So the inner set is ignored for the hashcode and is equal to the estimates, but is still available as a field.

+3


source to share


1 answer


The hashing Item

changes when changed content

. Since the set created Set(...)

is a hash set, it cannot work correctly if the hashes of its elements change. Note that it doesn't matter if it is Set[Item]

volatile or not; only what content

is mutable.



If you are putting mutable objects in a hashset or using them as hashmap keys, you must make sure that either 1) they are not mutable, and 2) their method hashCode

is stable.

+6


source







All Articles