Migration play from 2.2 to 2.3: No implicit view available from Any - scala

Try to migrate my project from play 2.2.7 to 2.3.8.
The project has the following code:
def setCoordinatesOfAddresses(cardId: Long, caller: Option[Tuple2[Float,Float]] = None, event: Option[Tuple2[Float,Float]] = None) {
Logger.debug("callling SC.setCoordinatesOfAddresses")
DB.withConnection { implicit c =>
try {
val query = SQL("Execute Sc.setCoordinatesOfAddresses {cardId}, {deviceLatitude}, {deviceLongitude}, NULL, NULL, {eventsLatitude}, {eventsLongitude}")
query.on(
"cardId" -> cardId,
"deviceLatitude" -> caller.map(_._1).getOrElse(null),
"deviceLongitude" -> caller.map(_._2).getOrElse(null),
"eventsLatitude" -> event.map(_._1).getOrElse(null),
"eventsLongitude" -> event.map(_._2).getOrElse(null) ).execute()
} catch {
case e: Throwable => Logger.error("error", e)
}
}
Logger.debug("SC.setCoordinatesOfAddresses called")
}
And compiler gives me this error:
Error:(384, 28) Play 2 Compiler:
../app/controllers/Cards.scala:384: No implicit view available from Any => anorm.ParameterValue.
"deviceLatitude" -> caller.map(_._1).getOrElse(null),
^
What should I do to solve this problem?
As I understand from documentation, I need to define parameter types. But I can't understand where and how to do that, in following code.

Try
val ps = Seq[anorm.ParameterValue](yourParameter1,yourParameter2) // Seq[ParameterValue]
SQL("SELECT * FROM test WHERE a={a} b={b}").
on('a -> ps(0), 'b -> ps(1))
You are using parameter of Any(or someother) type but the doc says to use anorm.ParameterValue type
Source

I would suggest to first try val p: ParameterValue = caller.
I think the issue is more that there is no specific parameter conversion for Tuple2[Float,Float] (btw (Float, Float)).
Before Anorm 2.3, unsafe conversion was using .toString (which can lead to a lot of issue).
The better is to convert the tuple to a formatted string, either before passing it as parameter or by adding a custom parameter conversion.
(Anorm doc indicates type safety issues, and how to implement conversion)

The getOrElse(null) is causing your problem. This is because you're calling getOrElse on an Option[Float]. However null in Scala cannot be assigned to a value type like Float. From the scaladoc:
Null is a subtype of all reference types; its only instance is the null reference. Since Null is not a subtype of value types, null is not a member of any such type. For instance, it is not possible to assign null to a variable of type scala.Int.
The same statement applies to Float. Since null and Float do not have a common super-type (other than Any), Scala infers the caller.map(_._1).getOrElse(null) as Any instead Float. This was allowed in Play 2.2.x, however in 2.3.x, Any is no longer allowed to be passed as a parameter because it is not type safe.
The solution? Just remove the getOrElse(null)s and you're good to go. caller.map(_._1) is an Option[Float] which Anorm knows how to handle whether it's empty or not. In general, using null in Scala is bad practice. If you see yourself calling getOrElse(null), you should ask yourself if perhaps there's a better way to handle it safely.

Related

Converting object of type Any into myClass, by passing the myClass as parameter

So I have a class:
case class Document (idx: String, name: String, code: String)
Due to some transformations, an object which was initially created as Document, now becomes of type Any.
val doc = Document("12", "anyName", "ps") // Ends up as type Any
So I want to convert it into type Document again.
I know that can be done like this:
val docNew = doc.asInstanceOf[Document]
But, what I am trying is to pass the type, in this case Document, as a parameter to make it more generic.
So I was trying the following:
val mType = Document
val docNew = doc.asInstanceOf[mType]
But Intellij says:
Cannot resolve symbol mType
Edit: My ultimate goal is to pass the parameter Document to a function, so at the end I could do something like:
def convertIntoDoc(doc: Any, mType: Type) = {
val docNew = doc.asInstanceOf[mType]
docNew
}
If you want to learn programming with Scala you have to learn about the difference between types and values.
Due to type-erasure type parameters never actually make it into your program. In reality, types only exist to help you write good code.
If you go down this road you will eventually realise that asInstanceOf[T] does not actually do anything.
You might think this is weird and with type-erasure the type system is superfluous, but let me assure you it is perfectly useful and when it comes to more complicated code actually becomes the stepping stone to generic programming, e.g. code that can be used in many different ways due to type parametrisation.
To spin this a little further you should almost never end up with a val of type Any because you will loose this additional safety net of static typing. This means you have already made a mistake somewhere upstream in your code.
Your ultimate goal is simple to achieve:
def convertIntoDoc[MType](doc: Any) = {
val docNew = doc.asInstanceOf[MType]
docNew
}
You just have to remember that MType is a type and not a variable. So it has to be used as type parameter and not as value parameter.
The problem is that casting an Any into a MType will get you ClassCastExceptions (when running your program!) if you use the wrong type.
asInstanceOf is very dangerous because it kind of overwrites the type safety that the Scala compiler provides.
If you have any questions about this let me know.
The correct way to convert your Any to Document is to use match:
val docNew = doc match { case d: Document => d }
This is safe because it will throw a MatchException if for some reason the object is not of type Document.
Your convertIntoDoc function is just a wrapper around asInstanceOf, so you need to give more detail on what this function is intended to do (preferably in a separate question).
instead of val you can use type
type mType = Document
val docNew = doc.asInstanceOf[mType]
For the second part of the question, you can pass the type using type parameter as argument
def convertIntoDoc[A](doc: Any) = {
val docNew = doc.asInstanceOf[A]
docNew
}

Null as parameter default value in scala produces type mismatch error

In order to make overloaded calls like
val myPage: DocumentType;
func()
func(myPage)
I wrote a function:
def func(page: DocumentType = null): Unit = {...}
but receive the following error:
type mismatch; found : Null(null) required: DocumentType
When I change DocumentType to String, the error disappears. First question: why?
DocumentType is a type from the library which I cannot change, with the following definition:
type DocumentType <: Document
trait Document
I do not want on each client call to wrap actual parameter to Option (like Option(myPage)) but are there any other options to obtain the similar?
You can just overload functions like
def func(): Unit = { } // do what you would do with null
def func(page: DocumentType): Unit = { } // do what you would do with a DocumentType
You can abstract the implementation by getting both to call some other private function to keep it DRY. You can then call func() or func(new DocumentType())
ORIGINAL ANSWER (not so good)
def func(page: DocumentType): Unit = func(Some(page))
def func(page: Option[DocumentType] = None): Unit = ???
means you don't need to resort to null. You lose the clean API, as you can call
val d = new DocumentType()
func()
func(d)
func(Some(d))
func(None)
Something like this should work:
trait Document
trait DocumentFunc {
// The trick is to tell the compiler that your type can be nullable.
type DocumentType >: Null <: Document
def fun(page: DocumentType = None.orNull): Unit = {
println(page)
}
}
Apparently, the problem is that since you only set the upper bound to Document, the compiler will reject null, because DocumentType could be overridden to be Nothing.
And "obviously", null could not be used in a place where a Nothing is expected.
First disclaimer: I agree with Joel Berkeley, that you should avoid null and I would prefer his solution.
I just wanted to answer the real question: "Why it does not work".
Second disclaimer: I used None.orNull just to not have an explicit null - that is just because the linters I use disallow the use of null.
You may change it if you want.
Third disclaimer: Type Members can almost always be changed by Type Parameters, which are (usually) more easier to use, and more "typesafe".
Type Members, IMHO, should only be used when you really need them, like path dependent types - More info can be found here.
Fourth disclaimer: The use of null and Unit (together with vars if you had), is a symptom of using Scala as Java, which is (usually) a bad use of the language. However, that is just my opinion.

Scala - Function's implicit return type

I am new to scala, and got a little doubt about function definition & default return type.
Here is a function definition:
def wol(s: String) = s.length.toString.length
The prompt says it's:
wol: (s: String)Int
But, the code didn't specify return type explicitly, shouldn't it default to Unit, which means void in Java.
So, what is the rules for default return type of a Scala function?
The return type in a function is actually the return type of the last expression that occurs in the function. In this case it's an Int, because #length returns an Int.
This is the work done by the compiler when it tries to infer the type. If you don't specify a type, it automatically gets inferred, but it's not necessarily Unit. You could force it to be that be stating it:
def wol(s: String): Unit = s.length.toString.length
EDIT [syntactic sugar sample]
I just remembered something that might be connected to your previous beliefs. When you define a method without specifying its return type and without putting the = sign, the compiler will force the return type to be Unit.
def wol(s: String) {
s.length.toString.length
}
val x = wol("") // x has type Unit!
IntelliJ actually warns you and gives the hint Useless expression. Behind the scene, the #wol function here is converted into something like:
// This is actually the same as the first function
def wol(s: String): Unit = { s.length.toString.length }
Anyway, as a best practice try to avoid using this syntax and always opt for putting that = sign. Furthermore if you define public methods try to always specify the return type.
Hope that helps :)

avoid type conversion in Scala

I have this weird requirement where data comes in as name ->value pair from a service and all the name-> value type is string only (which really they are not but that's how data is stored)
This is a simplified illustration.
case class EntityObject(type:String,value:String)
EntityObject("boolean","true")
now when getting that EntityObject if type is "boolean" then I have to make sure value is not anything else but boolean so first get type out and check value and cast value to that type. e.g in this case check value is boolean so have to cast string value to boolean to validate. If it was anything else besides boolean then it should fail.
e.g. if data came in as below, casting will fail and it should report back to the caller about this error.
EntityObject("boolean","1")
Due to this weird requirement it forces type conversion in validation code which doesn't look elegant and against type safe programming. Any elegant way to handle this in scala (may be in a more type safe manner)?
Here is where I'm going to channel an idea taken from a tweet by Miles Sabin in regards to hereogenous mappings (see this gist on github.) If you know the type of object mapping names a head of time you can use a nifty little trick which involves dependent types. Hold on, 'cause it's a wild ride:
trait AssocConv[K] { type V ; def convert: String => V }
def makeConv[V0](name: String, con: String => V0) = new AssocConv[name.type]{
V = V0
val convert = con
}
implicit val boolConv = makeConv("boolean", yourMappingFunc)
def convEntity(name: String, value: String)(implicit conv: AssocConv[name.type]): Try[conv.V] = Try{ conv.convert(value) }
I haven't tested this but it "should" work. I've also enclosed it in a Scala Try so that it catches exceptions thrown by your conversion function (in case you're doing things like _.toInt as the converter.)
You're really talking about conversion, not casting. Casting would be if the value really were an instance of Boolean at runtime, whereas what you have is a String representation of a Boolean.
If you're already working with a case class, I think a pattern matching expression would work pretty well here.
For example,
def convert(entity : EntityObject) : Any = entity match {
case EntityObject("boolean", "true") => true
case EntityObject("boolean", "false") => false
case EntityObject("string", s) => s
// TODO: add Regex-based matchers for numeric types
}
Anything that doesn't match one of the specified patterns would cause a MatchError, or you could put a catchall expression at the end to throw your own exception.
In this particular example, since the function returns Any, the calling coffee would need to do an actual type cast to get the specific type, but at least by that point all validation/conversion would have already been performed. Alternatively, you could just put the code that uses the values directly into the above function and avoid casting. I don't know what your specific needs are, so I can't offer anything more detailed.

Scala - mapping a list of integers to a method that receives java.lang.Object

Working in Scala-IDE, I have a Java library, in which one of the methods receives java.lang.Object. And I want to map a list of Int values to it. The only solution that works is:
val listOfInts = groupOfObjects.map(_.getNeededInt)
for(int <- listOfInts) libraryObject.libraryMethod(int)
while the following one:
groupOfObjects.map(_.getNeededInt).map(libraryMethod(_)
and even
val listOfInts = groupOfObjects.map(_.getNeededInt)
val result = listOfInts.map(libraryObject.libraryMethod(_))
say
type mismatch; found : Int required: java.lang.Object Note: an
implicit exists from scala.Int => java.lang.Integer, but methods
inherited from Object are rendered ambiguous. This is to avoid a
blanket implicit which would convert any scala.Int to any AnyRef. You
may wish to use a type ascription: x: java.lang.Integer.
and something like
val result = listOfInts.map(libraryObject.libraryMethod(x => x.toInt))
or
val result = listOfInts.map(libraryObject.libraryMethod(_.toInt))
does not work also.
1) Why is it happening? As far as I know, the for and map routines do not differ that much!
2) Also: what means You may wish to use a type ascription: x: java.lang.Integer? How would I do that? I tried designating the type explicitly, like x: Int => x.toInt, but that is too erroneus. So what is the "type ascription"?
UPDATE:
The solution proposed by T.Grottker, adds to it. The error that I am getting with it is this:
missing parameter type for expanded function ((x$3) => x$3.asInstanceOf[java.lang.Object])
missing parameter type for expanded function ((x$3) => x$3.asInstanceOf{#null#}[java.lang.Object]{#null#}) {#null#}
and I'm like, OMG, it just grows! Who can explain what all these <null> things mean here? I just want to know the truth. (NOTE: I had to replace <> brakets with # because the SO engine cut out the whole thing then, so use your imagination to replace them back).
The type mismatch tells you exactly the problem: you can convert to java.lang.Integer but not to java.lang.Object. So tell it you want to ask for an Integer somewhere along the way. For example:
groupOfObjects.map(_.getNeededInt: java.lang.Integer).map(libraryObject.libraryMethod(_))
(The notation value: Type--when used outside of the declaration of a val or var or parameter method--means to view value as that type, if possible; value either needs to be a subclass of Type, or there needs to be an implicit conversion that can convert value into something of the appropriate type.)