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.
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
}
}
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).
Related
I have this trait with a single method of type WSResponse => HTTPCallResult[A]
trait Parsable[A] {
def parse(response: WSResponse): HTTPCallResult[A]
}
I want to define an implicit conversion from a function WSResponse => A
object Parsable {
implicit class DefaultResponseParser[A](parser: WSResponse => A) extends Parsable[A] {
override def parse(r: WSResponse): HTTPCallResult[A] = {
//implementation
}
}
}
The desired behaviour is such, that if a function WSResponse => HTTPCallResult[A] is passed the anonymous class of Parsable[A] is automatically created. If a function of any other return type is passed (WSResponse => A) the implicit conversion is triggered.
However, an error occurs when compiling with SBT
[error] /Auth.scala:24:60: type mismatch;
[error] found : String
[error] required: HTTPCall.HTTPCallResult[?]
[error] (which expands to) scala.util.Either[String,?]
[error] .post((r: WSResponse) => (r.json \ "key").as[String])
This function was used in order to test it.
def post[A](parser: Parsable[A])
.post((r: WSResponse) => (r.json \ "key").as[String])
EDIT 1:
Even making the implicit class an implicit method and moving it to the very same scope as post didn't help.
EDIT 2:
It seems that the problem stems from the use of trait with single undefined method. Therefore when passed a function to the post method, the compiler tries to create an anonymous class of type Parser[A] from that. Due to a type missmatch it throws, without even trying to be looking for any implicits.
I have the following code, that does not get compiled:
final class DbSystemEnvironment[F[_] : MonadError[F, Throwable]] private(env: Environment[F])
extends DbSetting[F] {
override def read(url: String, user: String, pw: String): F[DbParameter] =
(for {
a <- OptionT(env.get(url))
b <- OptionT(env.get(user))
c <- OptionT(env.get(pw))
} yield DbParameter(a, b, c))
.value
.flatMap {
case Some(v) => v.pure[F]
case None => DbSettingError.raiseError[F, DbParameter]
}
}
The compiler complains:
[error] db/DbSystemEnvironment.scala:10:38: cats.MonadError[F,Throwable] does not take type parameters
[error] final class DbSystemEnvironment[F[_] : MonadError[F, Throwable]] private(env: Environment[F])
[error] ^
[error] db/DbSystemEnvironment.scala:16:9: Could not find an instance of Functor for F
[error] c <- OptionT(env.get(pw))
[error] ^
[error] db/DbSystemEnvironment.scala:20:27: value pure is not a member of Any
[error] case Some(v) => v.pure[F]
[error] ^
[error] db/DbSystemEnvironment.scala:21:37: value raiseError is not a member of object io.databaker.db.DbSettingError
[error] case None => DbSettingError.raiseError[F, DbParameter]
It seems, that I do not use MonadError correctly.
The rest of the code:
final case class DbParameter(url: String, user: String, pw: String)
trait Environment[F[_]] {
def get(v: String) : F[Option[String]]
}
object Environment {
def apply[F[_]](implicit ev: Environment[F]): ev.type = ev
def impl[F[_]: Sync]: Environment[F] = new Environment[F] {
override def get(v: String): F[Option[String]] =
Sync[F].delay(sys.env.get(v))
}
}
How to get the code compiled?
The issue here is the constraint syntax. For a type constructor with a single parameter (like Monad), you can write class Foo[F[_]: Monad]. When you need to "partially apply" a type constructor with multiple parameters, like MonadError, the situation is slightly different.
If you're using kind-projector, you can write the following:
class DbSystemEnvironment[F[_]: MonadError[*[_], Throwable]]
This is non-standard syntax, though, and it isn't currently included in Dotty's partial -Ykind-projector compatibility support. I'd recommend just desugaring the implicit parameter list:
class DbSystemEnvironment[F[_]](implicit F: MonadError[F, Throwable]])
This does exactly what you want, doesn't require an extra compiler plugin, and is much more future-proof.
I have a method that should dynamically cast a field member into a certain type depending on a configuration flag format.
This flag format, accepts one of the following type values:
object Types {
val Str = "string"
val IntNum1 = "int"
val IntNum2 = "integer"
val DoubleNum = "double"
val LongNum = "long"
}
One option would be to use reflection. Another option would be to use pattern matching (the method I'm trying to do this with)
Here's the method for String types:
private def getValClassIfStr(format: String): Class[String] = {
format.toLowerCase match {
case Types.Str => classOf[String]
case _ => null
}
}
And Here's the method for Numerical types, extending from AnyVal, that fails to compile:
private def getValueClass[T <: AnyVal](format: String): Try[Class[T]] = {
format.toLowerCase match {
case Types.IntNum1 || Types.IntNum2 => Success(classOf[Int])
case Types.DoubleNum => Success(classOf[Double])
case Types.LongNum => Success(classOf[Long])
case _ => Failure(new Exception)
}
}
The second method doesn't compile because of a:
Type mismatch: required Try[Class[T]] found Try[Class[Int]]
Which I don't understand, given T <: AnyVal.
Any idea? and if that's a bad approach, what would a "clean" alternative be?
I think the reason why this doesn't work becomes clearer once you replace Class[T] in the return value with Class[AnyVal]:
type mismatch;
found : Class[Int](classOf[scala.Int])
required: Class[AnyVal]
Note: Int <: AnyVal, but Java-defined class Class is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: AnyVal`. (SLS 3.2.10)
In other words, any call to getValueClass[T] would always have to be populated with T = AnyVal by the compiler, since format is only evaluated at runtime. This, however, is not possible since Class[T] is invariant, so you can't return a Class[Int] and a Class[Double] as a Class[AnyVal], since for invariant containers there's no subtyping relationship.
To demonstrate:
var x: Class[AnyVal] = _
x = classOf[Int]
// Boom
Lets say I want to write generic function foo that will use pattern matching to check whether passed argument is of type of it's generic argument T
Naive attempt:
def foo[T]: PartialFunction[Any, Boolean] = {
case x: T =>
true
case _ =>
false
}
... won't work since T gets ereased. Compiller warning confirms that:
Warning:(11, 13) abstract type pattern T is unchecked since it is eliminated by erasure
case x: T =>
^
What is the best way to get it work?
Scala has introduced ClassTags for this purpose. They can be obtained by an implicit parameter, and will be automatically provided, which means you don't have to worry about the parameter when calling the method:
import scala.reflect.ClassTag
def foo[T](implicit tag: ClassTag[T]): PartialFunction[Any, Boolean] = {
case x: T =>
true
case _ =>
false
}
val isString = foo[String] // ClassTag gets provided implicitly here
isString("Hallo") // will return true
isString(42) // will return false
For further explanations see the docs.
Fiddling with sample code demonstrating type bounds, I changed the original code below from using a case class to a plain class, for the definition of class MyInt, the only class in this snippet.
trait Similar {
def isSimilar(x: Any): Boolean
}
class MyInt(x: Int) extends Similar {
def isSimilar(m: Any): Boolean =
m.isInstanceOf[MyInt] &&
m.asInstanceOf[MyInt].x == x
}
object UpperBoundTest extends App {
def findSimilar[T <: Similar](e: T, xs: List[T]): Boolean =
if (xs.isEmpty) false
else if (e.isSimilar(xs.head)) true
else findSimilar[T](e, xs.tail)
val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
println(findSimilar[MyInt](MyInt(4), list))
println(findSimilar[MyInt](MyInt(2), list))
}
That no longer compiles
[error] 7: type mismatch;
[error] found : MyInt
[error] required: ?{def x: ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A]
[error] and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
[error] are possible conversion functions from MyInt to ?{def x: ?}
[error] m.asInstanceOf[MyInt].x == x
[error] ^
This is an interesting case to me, as sometimes I find myself refactoring case classes to plain classes while refactoring inheritance, and clearly some changes need to made in the code in order to enjoy a smooth transition that preserves the code working.
Switching .AsInstanceOf to an equivalent match (m match {case m:MyInt => m.x == x; case _ => false}) yields the same compilation error. Using a more naive match does not compile either:
trait Similar {
def isSimilar(x: Any): Boolean
}
class MyInt(x: Int) extends Similar {
def isSimilar(m: Any): Boolean = {
m match {case m:MyInt => true; case _ => false}
}
}
object UpperBoundTest extends App {
val a = new MyInt(4)
def findSimilar[T <: Similar](e: T, xs: List[T]): Boolean =
if (xs.isEmpty) false
else if (e.isSimilar(xs.head)) true
else findSimilar[T](e, xs.tail)
val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
println(findSimilar[MyInt](MyInt(4), list))
println(findSimilar[MyInt](MyInt(2), list))
}
18: not found: value MyInt
[error] val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
[error] ^
18: not found: value MyInt
[error] val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
[error] ^
18: not found: value MyInt
[error] val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
[error] ^
19: not found: value MyInt
[error] println(findSimilar[MyInt](MyInt(4), list))
[error] ^
20: not found: value MyInt
[error] println(findSimilar[MyInt](MyInt(2), list))
[error] ^
[error] 5 errors found
Are non-case classes a practice to be enitrely discouraged other than using them for inheriting them, or when you will never need to check their type? when would you ever use a non-case class?
Simply declare your class as
class MyInt(val x: Int) extends Similar
For case classes val is the default, whereas on regular classes you need to explicitly add it to signal that you want to synthesize the accessors for the constructor parameters
Also, in case classes a companion object providing a default apply method is automatically synthesized, allowing you to call
MyInt(2)
as opposed to
new MyInt(2)
You either have to use the latter, or manually provide an apply method in a companion object.
Bottom line, if you need to match on a class, case classes are much more convenient, as you can skip the downcast (which is implicitly performed when you match on the type doing x: MyInt)
Classes are not discouraged, simply case-classes are much more convenient in your specific use -case
Complete code you need to avoid compilation failure in any case, including pattern matching:
class MyInt(val x: Int) extends Similar
object MyInt {
def apply(x: Int) = new MyInt(x)
// if more than one field, return Some(tuple of all fields)
def unapply(myInt: MyInt): Option[Int] = Some(myInt.x)
}
If you also want behavior to be the same as original, you need to define equals and hashCode methods as well:
class MyInt(val x: Int) extends Similar {
def equals(y: Any) = y match {
case MyInt(z) => x == z
case _ => false
}
def hashCode = x
}