scalaakkaakka-http

Scala Type Mismatch Error when creating a Map


I'm using scala 3.3 to build a map variable that temporarily stores a school's information like below.

Map's variable:


"staff" -> Set[CreateStaff]
"students" -> Set[CreateStudent]
"books" -> Set[CreateBook]

The map stores data inside heterogenous Set() parameters.

The data is generated using case classes CreateStaff, CreateStudent and CreateBook - traits of School.

And I try to store the data inside the map variable above using the code mapOS("staff")+=newStaffA which gives an error like below.

The same errors occur for the CreateStudent and CreateBook case classes , which I've omitted in the error text.

Error:


error: type mismatch;
found: Map[String,scala.collection.mutable.Set[_ >: this.CreateBook with this.CreateStudent with this.CreateStaff <: Product with this.School with java.io.Serializable]] (in scala.collection.mutable)
required: Map[String,Set[this.School]] (in scala.collection.immutable)
val mapOS: Map[String, Set[School]] = mutable.Map("staff" -> mutable.Set[CreateStaff](), "students" -> mutable.Set[CreateStudent](), "books" -> mutable.Set[CreateBook]())

error: value += is not a member of Set[this.School]
Expression does not convert to assignment because receiver is not assignable.
mapOS("staff")+=newStaffA

... OMITTED SIMILAR ERRORS FOR CreateStudent and CreateBook case classes
...             

My current code looks like below.

Could you help me identify and fix the errors!

Thanks in advance for your help!

school.scala:



import scala.collection.immutable
import scala.collection.mutable

sealed trait School

final case class CreateStaff(id: String, name: String) extends School
final case class CreateStudent(id: String, name: String) extends School
final case class CreateBook(id: String, name: String) extends School

val mapOS: Map[String, Set[School]] = mutable.Map("staff" -> mutable.Set[CreateStaff](), "students" -> mutable.Set[CreateStudent](), "books" -> mutable.Set[CreateBook]())

val newStaffA: CreateStaff = CreateStaff("id1", "name1")
val newStaffB: CreateStaff = CreateStaff("id1", "name1")

val newStudentA: CreateStudent = CreateStudent("id1", "name1")
val newStudentB: CreateStudent = CreateStudent("id1", "name1")

val newBookA: CreateBook = CreateBook("id1", "name1")
val newBookB: CreateBook = CreateBook("id1", "name1")


mapOS("staff")+=newStaffA
mapOS("staff")+=newStaffB

mapOS("students")+=newStudentA
mapOS("students")+=newStudentB

mapOS("books")+=newBookA
mapOS("books")+=newBookB

println(mapOS.getOrElse("staff", Set.empty))


Solution

  • To build on a comment I had with regard to have a class instead of a map, here is an example of how this would look like if it was modeled as such:

    final case class CreateStaff(id: String, name: String)
    final case class CreateStudent(id: String, name: String)
    final case class CreateBook(id: String, name: String)
    
    final case class School(
      staff: Set[CreateStaff] = Set.empty[CreateStaff],
      students: Set[CreateStudent] = Set.empty[CreateStudent],
      books: Set[CreateBook] = Set.empty[CreateBook],
    )
    
    val school = School()
    
    val staff = CreateStaff("id1", "name1")
    val student = CreateStudent("id1", "name1")
    val book = CreateBook("id1", "name1")
    
    val updatedSchool = school.copy(
      staff = school.staff + staff,
      students = school.students + student,
      books = school.books + book,
    )
    
    println(updatedSchool.staff) // prints "Set(CreateStaff(id1,name1))"
    

    This code is available for you to play around with here on Scastie.

    A few comments on the decisions I took:

    For completeness, this is the same example using mutable data structures instead:

    import scala.collection.mutable
    
    final case class CreateStaff(id: String, name: String)
    final case class CreateStudent(id: String, name: String)
    final case class CreateBook(id: String, name: String)
    
    final class School(
      val staff: mutable.Set[CreateStaff] = mutable.Set.empty[CreateStaff],
      val students: mutable.Set[CreateStudent] = mutable.Set.empty[CreateStudent],
      val books: mutable.Set[CreateBook] = mutable.Set.empty[CreateBook],
    )
    
    val school = new School()
    
    val staff = CreateStaff("id1", "name1")
    val student = CreateStudent("id1", "name1")
    val book = CreateBook("id1", "name1")
    
    school.staff += staff
    school.students += student
    school.books += book
    
    println(school.staff) // prints "HashSet(CreateStaff(id1,name1))"
    

    You can play around with this code here on Scastie.