Home > Blockchain >  Why is pattern matching ok in scala but using instanceof is a sign of bad code in Java
Why is pattern matching ok in scala but using instanceof is a sign of bad code in Java

Time:02-03

There is an aspect of the pattern matching I don't understand.

In the documentation of the pattern matching they show an example such as :

https://docs.scala-lang.org/tour/pattern-matching.html

abstract class Notification

case class Email(sender: String, title: String, body: String) extends Notification

case class SMS(caller: String, message: String) extends Notification

case class VoiceRecording(contactName: String, link: String) extends Notification

def showNotification(notification: Notification): String = {
  notification match {
    case Email(sender, title, _) =>
      s"You got an email from $sender with title: $title"
    case SMS(number, message) =>
      s"You got an SMS from $number! Message: $message"
    case VoiceRecording(name, link) =>
      s"You received a Voice Recording from $name! Click the link to hear it: $link"
  }
}
val someSms = SMS("12345", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")

Which could be somewhat recoded in java such as :

Notification notification = /* Init a notification instance */

if(notification instanceof Email) {
    Email currentEmail = (Email) notification;
    currentEmail.doSomething();
} else if (notification instanceof SMS) {
    SMS currentSMS = (SMS) notification;
    currentSMS.doSomething();
} else if {
    /* ... */
}

Pattern matching seems to be very positively seen but on the opposite the java equivalent is seen as a "code smell" or a bad pattern.

From my understand they are doing the same thing and maybe technically as well, it's just hidden for the scala pattern matching.

Yet such a double standard wouldn't stay unseen so I guess there is something wrong with my understanding.

CodePudding user response:

Under the hood, Scala pattern matching often boils down to code that's exactly like the if (notification instanceof Email) { ... } else if (notification instanceof SMS) Java code.

The particular example you give, of an abstract class Notification which isn't sealed is one where the Scala code is no better (except perhaps expressing overall intent more clearly) than the if/instanceof tree.

This is because the main benefit of pattern matching is the possibility of exhaustivity checking. With the if/instanceof approach and the example of pattern matching you present, you aren't going to be alerted that you haven't handled every case (e.g. you left off the VoiceRecording case).

By making Notification sealed (e.g. sealed abstract class Notification), the Scala compiler will ensure that no Scala code in other files (technically, compilation units, which are for all intents and purposes files) can extend Notification; since it now knows all the possible Notifications, it can then raise a compiler error if you miss a case. There's no reliable way to do this in the if/instanceof case because that's a lower level of abstraction.

CodePudding user response:

The "smell" has been historic. Object oriented design suggests you should be able to let the type hierarchy dispatch your method call to the appropriate subtype, rather than checking for actual instances at the call site. There had been some bad designs related to overuse of inheritance, which had lead to such instanceof usage. The instanceof usage wasn't the bad thing, but it hinted at the type hierarchy possibly being bad.

On the other hand, Java 17 now has Scala's pattern matching, too (as a preview feature, soon to be finalised), so you can't really say that using instanceof is a bad thing in Java.

  •  Tags:  
  • Related