11

My intention is to change the behaviour of the == method in String to call equalsIgnoreCase.

This code

implicit class LowerCase(s: String) {
      override def ==(that: LowerCase) = that.equalsIgnoreCase(this)
}

results in this error

error: type mismatch;
 found   : MyClass.LowerCase
 required: String
      override def ==(that: String) = that.equalsIgnoreCase(this)
2
  • What do you mean by "does not work"? Do you get errors? Does it behave differently from what you expect? What did you expect and what does it do in reality, how does it differ from what you expected? Commented Dec 20, 2013 at 8:22
  • Yes, added compiler error message Commented Dec 20, 2013 at 8:27

1 Answer 1

18

In case there is already such method in class scala compiler would not search for implicit conversion.

Note that your implementation is invalid, it should be:

implicit class LowerCase(val s: String) {
      def ==(that: LowerCase) = that.s.equalsIgnoreCase(this.s)
}

Note that it's still useless.

In case you want to use it as Map's key you should specify type manually:

implicit class LowerCase(val s: String) {
      // Use `equals`, not `==`
  override def equals(that: Any) = that match {
    case t: LowerCase => t.s.equalsIgnoreCase(this.s)
    case _ => false
  }

  // Don't forget to override hashCode for Map and Set
  override lazy val hashCode = s.toLowerCase.hashCode

  override def toString() = s
}

scala> Set[LowerCase]("A", "a", "b")
res0: scala.collection.immutable.Set[LowerCase] = Set(A, b)

If you want to use this method with variables like this "a" == "A" you should use another method name:

implicit class LowerCase(val s: String) extends AnyVal {
      def ===(that: String) = s.equalsIgnoreCase(that)
}

scala> "a" === "A"
res0: Boolean = true
Sign up to request clarification or add additional context in comments.

5 Comments

Is there a way to override a class method implicitly, i.e. without extending and manually overriding the superclass' method?
There are still errors: remove override, and the constructor parameter needs to be a val. But even then it won't work, because of what you mentioned (Scala has no reason to search for an implicit conversion).
Thank you very much senia, @Jesper. Indeed, defining a new method is much cleaner.
@hanxue: Note that there is already a method === (and =/=) in scalaz (see Scalaz cheat sheet), and you could override it's behavior using implicit object IgnoreCaseEqual extends new Equal[String] { def equal(s1: String, s2: String) = s1.equalsIgnoreCase(s2) }, but you'll have to hide a default implementation like this: import Scalaz.{stringInstance => _, _}.
Thanks senia. Not using scalaz for this particular application because it is really simple. Your answer is exactly what I needed :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.