0

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.

Community
  • 1
  • 1
aa8y
  • 3,854
  • 4
  • 37
  • 62

2 Answers2

1

Other than the fact that toBoolean does not override anything, your implementation is fine. However, as the compiler error helpfully indicates, the name of your method clashes with the toBoolean method in the automatically imported StringOps class in Predef. As a result, there is more than one implicit conversion that could be applied and the compiler cannot decide which one to use. This is why the error indicates that there is ambiguity. The solution is to name your method differently, so the following should work.

implicit class MyString(s: String) {
  def toBooleanAlt = s.trim.toLowerCase match {
    case "true" | "t" | "1" => true
    case _ => false
  }
}
moem
  • 556
  • 3
  • 10
0

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).

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487