Search code examples
scalaimplicit

Implicit class for overriding String.toBoolean


I tried following this answer, but it did not help. Here's the implementation I have.

implicit class MyString(s: String) {
  override def toBoolean = s.trim.toLowerCase match {
    case "true" | "t" | "1" => true
    case _ => false
  }
}

And the error I am getting is:

[error]  found   : s.type (with underlying type String)
[error]  required: ?{def toBoolean: ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error]  both method augmentString in object Predef of type (x: String)scala.collection.immutable.StringOps
[error]  and method MyString in trait ImplicitsStartingWithS of type (s: String)foo.MyString
[error]  are possible conversion functions from s.type to ?{def toBoolean: ?}
[error]           case Some(s) => s.toBoolean
[error]                           ^

I can't seem to find what's wrong with the code.


Solution

  • First, note that implicit conversions can't override methods in the type being converted from: if such a method exists, the compiler simply won't look for the implicit! There is a fork of Scala called Scala-Virtualized which does allow this (you'd define a method infix_toBoolean(x: String)), but I'd recommend against it for general usage: if you can't live without this feature check it out.

    In this case, as @moem's answer says, the toBoolean isn't actually defined on String. As an alternative to simply giving a different name to your toBoolean, you can also explicitly hide augmentString in a class by defining something else with this name: def augmentString = ??? or

    class MyString(s: String) {
      def toBoolean = s.trim.toLowerCase match {
        case "true" | "t" | "1" => true
        case _ => false
      }
    }
    
    implicit def augmentString(s: String) = new MyString(s)
    

    Of course, this loses all other methods provided by this implicit as well, but you can provide them in MyString (e.g. by extending StringOps).