Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the reasons and/or benefits Scala can compare incompatible objects?

This puzzles me -- I have read the reasons Scala exists at all, and the common-sense presented appeals to me, for example choosing static typing (because of less errors). Yet, you can compare (out of the box, by default) completely different, irrelevant objects and it compiles and runs fine. For me it just begs for more errors in code.

Could someone please explain what are the reasons for such feature? Or benefits?

I know how Scala works in the matter of comparison. I am asking WHY it works that way.

I would expect, that if I want to do this, I would write implicit conversion or explicit comparison. That approach makes perfect sense for me, current Scala way -- no, and thus my question.

And one more thing -- I am not looking how to use Scala-way comparison for some fancy effects, I am looking for more strict error checking. IOW: I don't want to compare Orange and Apple by color, I want to forbid such comparison by default unless user explicitly say it is OK to compare such types.

Example

class Test
{
  val s : String = "ala"
}

class Foo
{
  val x : Int = 5
}

object Testbed 
{
  def main(args : Array[String])
  {
    val t = new Test
    val f = new Foo
    if (t==f)
      println("match")
    else
      println("no")
  }
}
like image 693
greenoldman Avatar asked Sep 07 '11 09:09

greenoldman


2 Answers

Well, the simple answer is that == is designed to be compatible with java.lang.Object.equals(). Since any class can override equals() it's impossible for the Scala compiler to determine the result of an equality check between two objects unless it knows the runtime class of the object at compile time (i.e. the static type must be a final class or the new invocation must be visible to the compiler when compiling the equality check) AND the equals() method is not overridden in this class or any super class.

So, in your example the compiler can indeed infer the runtime class of both t and f and issue a warning (not an error though) for the equality check, but in practice the cases where the runtime class can be inferred are quite rare. Note that scalac already issues warnings for some equality comparisons between primitive types and object types.

P.S. If you want a safer equality check use the Equal trait in Scalaz.

like image 80
Jesper Nordenberg Avatar answered Jan 03 '23 20:01

Jesper Nordenberg


Equality in scala is value equality (not reference) and what is equal to what can be defined by you by overriding equals. Basically == is not an operator in scala, but acts like (and in fact IS) a method on the object that you want to test for equality. So t == f is actually t.==(f) where == is defined on Any, so you get it on every class in scala.

For instance (in your example) you can make your Test == to a Foo, like this:

class Test {
  val s : String = "ala"
}

class Foo {
  val x : Int = 5
  override def equals(that: Any) : Boolean = {
    that.isInstanceOf[Test] && this.x == 5 && that.asInstanceOf[Test].s=="ala";
  }  
}

and now you get:

scala> val t = new Test
t: Test = Test@86a58a

scala> val f = new Foo
f: Foo = Foo@104f889

scala> f==t
res3: Boolean = true

but (since we have NOT overridden equals on Test)

scala> t==f
res4: Boolean = false

While in this specific case this does not make a lot of sense, the point is that scala lets you decide what makes a Test equal to a Foo. Do you want a Person to be == to another Person (or to an Employee) if they have the same social security number? You can implement that logic.

However, with great power comes great responsibility and in fact the concept of equality is surprisingly tricky.

like image 38
Paolo Falabella Avatar answered Jan 03 '23 21:01

Paolo Falabella