Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pattern-match a nested class in Scala?

I've tried the code below (the equal method is written after Programming in Scala book)

class Person() {
    class Room(r: Int, c: Int) {
        val row = r
        val col = c

        override def hashCode: Int =
            41 * (
                41 + row.hashCode
            ) + col.hashCode

        override def equals(other: Any) =
            other match {
                case that: Room =>
                   (that canEqual this) &&
                   this.row == that.row &&
                   this.col == that.col
               case _ => false
            }

        def canEqual(other: Any) =
            other.isInstanceOf[Room]
    }

    val room = new Room(2,1)
}

val p1 = new Person()
val p2 = new Person()

println(p1.room == p2.room)
>>> false

After some analysing I found that Scala redefines the class Room for each instance of Person and that's the reason the two rooms aren't equal.

One possibility to resolve the problem is to put the class outside of the class Person, but this isn't always what's easiest. (For example if the class has to access some parameters of Person.)

What alternatives are there to write the equal method?

like image 835
Georg Schölly Avatar asked Dec 02 '11 11:12

Georg Schölly


People also ask

How do you match a pattern in Scala?

A pattern match includes a sequence of alternatives, each starting with the keyword case. Each alternative includes a pattern and one or more expressions, which will be evaluated if the pattern matches. An arrow symbol => separates the pattern from the expressions.

Does Scala have pattern matching?

Notes. Scala's pattern matching statement is most useful for matching on algebraic types expressed via case classes. Scala also allows the definition of patterns independently of case classes, using unapply methods in extractor objects.

Which method of case class allows using objects in pattern matching?

Case classes are Scala's way to allow pattern matching on objects without requiring a large amount of boilerplate. In the common case, all you need to do is add a single case keyword to each class that you want to be pattern matchable.

What is the use of Scala pattern matching?

Pattern matching is a way of checking the given sequence of tokens for the presence of the specific pattern. It is the most widely used feature in Scala. It is a technique for checking a value against a pattern. It is similar to the switch statement of Java and C.


1 Answers

The problem is that your two rooms are instances of a path-dependent type: their types are p1.Room and p2.Room:

scala> :type p1.room
p1.Room

One way to make this work is to refer to Room using type selection, i.e. as Person#Room.

class Person() {
    class Room(r: Int, c: Int) {
        val row = r
        val col = c

        override def hashCode: Int = // omitted for brevity

        override def equals(other: Any) =
            other match {
                case that: Person#Room =>
                   (that canEqual this) &&
                   this.row == that.row &&
                   this.col == that.col
               case _ => false
            }

        def canEqual(other: Any) =
            other.isInstanceOf[Person#Room]
    }

    val room: Room = new Room(2,1)
}

val p1 = new Person()
val p2 = new Person()

scala> p1.room == p2.room
res1: Boolean = true
like image 114
Ben James Avatar answered Oct 08 '22 01:10

Ben James