(Scala 2.12.8) pattern type is incompatible with expected type for parameterized type inside of parameterized class - scala

(Scala 2.12.8)
Full Example
So lets say you have some "TypeEvidence" for some specific concrete types:
sealed trait TypeEvidence[+T]
object TypeEvidence{
case object DoubleType extends TypeEvidence[Double]
case object LongType extends TypeEvidence[Long]
case object StringType extends TypeEvidence[String]
}
I can match on those evidence objects like this:
object ThisIsOk{
def apply[T](ev: TypeEvidence[T]): Option[T] = {
ev match {
case TypeEvidence.DoubleType => Some(123.456)
case TypeEvidence.LongType => Some(1234L)
case _ => None
}
}
}
But not like this:
class ThisFails[T]{
def apply(ev: TypeEvidence[T]): Option[T] = {
ev match {
case TypeEvidence.DoubleType => Some(123.456)
case TypeEvidence.LongType => Some(1234L)
case _ => None
}
}
}
This fails to compile with:
pattern type is incompatible with expected type;
found : TypeEvidence.DoubleType.type
required: TypeEvidence[T]
pattern type is incompatible with expected type;
found : TypeEvidence.LongType.type
required: TypeEvidence[T]
Why is this? And how can this be worked around?

What if you do this with a type class?
class ThisFails[T]{
def apply(ev: TypeEvidence[T])(implicit
teto: TypeEvidenceToOption[T]
): Option[T] = teto(ev)
}
trait TypeEvidenceToOption[T] {
def apply(ev: TypeEvidence[T]): Option[T]
}
object TypeEvidenceToOption {
implicit val double: TypeEvidenceToOption[Double] =
{ case TypeEvidence.DoubleType => Some(123.456) }
implicit val long: TypeEvidenceToOption[Long] =
{ case TypeEvidence.LongType => Some(1234L) }
implicit def default[T]: TypeEvidenceToOption[T] = _ => None
}
new ThisFails[Double].apply(TypeEvidence.DoubleType) // Some(123.456)
new ThisFails[Long].apply(TypeEvidence.LongType) // Some(1234)
new ThisFails[String].apply(TypeEvidence.StringType) // None

I'm not entirely sure why it didn't work the way you expected. The only reasonable explanation I tell to myself is that the compiler has no issue using T as a placeholder for any type while T belongs to the parameterized method, whereas when it belongs to a parameterized class, it's more restrictive in terms of what you can do with it.
As a workaround, you can use .type and .asIstanceOf:
class ThisFails[T] {
def apply(ev: TypeEvidence[T]): Option[T] = {
ev match {
case _: TypeEvidence.DoubleType.type => Some(123.456.asInstanceOf[T])
case _: TypeEvidence.LongType.type => Some(1234L.asInstanceOf[T])
case _ => None
}
}
}
val x = new ThisFails[Long]
val x2 = new ThisFails[Double]
val x3 = new ThisFails[String]
println(x.apply(TypeEvidence.LongType)) // Some(1234)
println(x2.apply(TypeEvidence.DoubleType)) // Some(123.456)
println(x3.apply(TypeEvidence.StringType)) // None
I'm aware it's not nice, but you asked for a workaround. This pattern match now matches an object of the given type. Of course, with this workaround, having the objects "caseable" is redundant now.
I had a peek at the disassembled code of object ThisIsOk to figure out this workaround:
public static class ThisIsOk$
{
public static final ThisIsOk$ MODULE$;
static {
ThisIsOk$.MODULE$ = new ThisIsOk$();
}
public <T> Option<T> apply(final Main.TypeEvidence<T> ev) {
Object module$;
if (Main.TypeEvidence$.DoubleType$.MODULE$.equals(ev)) {
module$ = new Some((Object)BoxesRunTime.boxToDouble(123.456));
}
else if (Main.TypeEvidence$.LongType$.MODULE$.equals(ev)) {
module$ = new Some((Object)BoxesRunTime.boxToLong(1234L));
}
else {
module$ = None$.MODULE$;
}
return (Option<T>)module$;
}
}
I saw here the way pattern match works is by calling equals on their types, but since equals is not overridden, what this actually does is a reference check. Recall:
// in Object.java file:
public boolean equals(Object obj) {
return (this == obj);
}
Also I saw a cast to Option<T> in the end.
So with these observations, the class ThisFails[T] workaround I just showed earlier gets disassembled into this:
public static class ThisFails<T>
{
public Option<T> apply(final Main.TypeEvidence<T> ev) {
Object module$;
if (Main.TypeEvidence$.DoubleType$.MODULE$ == ev) {
module$ = new Some((Object)BoxesRunTime.boxToDouble(123.456));
}
else if (Main.TypeEvidence$.LongType$.MODULE$ == ev) {
module$ = new Some((Object)BoxesRunTime.boxToLong(1234L));
}
else {
module$ = None$.MODULE$;
}
return (Option<T>)module$;
}
}
Which is almost identical to the object ThisIsOk's disassembled code, except for using == instead of equals, which does not matter in this case, as I explained earlier.
I tested it with both Scala 2.13.8 and your version here on Scastie, and both worked.

Related

Scala pattern matching type with inherited classes

I have a series of inherited classes,with some more methods than the base class. Like this:
class Animal
{
var Name: String
}
class Fish extends Animal
{
def swim()
{
println("I'm a Fish and i'm swimming!");
}
}
class Turtle extends Animal
{
def swim()
{
println("I'm a Turtle and i'm swimming!");
}
}
I would like to use the type match pattern to a generic Animal class, to recognize the exact type and apply the swim() method if it can, like this:
myAnimal match {
case m:Fish => m.Swim()
case m:Turtle => m.Swim()
case _: => doSomethingElse()
}
I would like to write it in an elegant way, avoiding to repeat continuously the lines.
I know that I can do this:
myAnimal match {
case (_:Fish | _:Turtle) => println("I can do this!")
}
And I know, as I wrote above, that I can do:
myAnimal match {
case m:Fish => m.swim()
}
but, I can't put them in or, like this
myAnimal match {
case (m:Fish | m:Turtle) => m.swim() //ERROR (cannot recognize swim() method)
//Not even this
case m # (_:Fish | _:Turtle) => m.swim() //ERROR (cannot recognize swim() method)
case _: => doSomethingElse()
}
A good solution would be to insert an intermediate class, like AnimalsThatCanSwim that extend Animals. This solution should be the last option, because I have to avoid changing the extended classes.
You can use structural types combined with an extractor that uses reflection to check if your object has a swim method. Thanks to Mateusz Kubuszok and Dmytro Mitin, I now have a solution that seems to work.
Use like this:
myAnimal match {
case CanSwim(m) => m.swim()
case _ => println("Boohoo, I can't swim!")
}
The other stuff:
import scala.reflect.runtime.universe._
type CanSwim = { def swim(): Unit }
object CanSwim {
def unapply(arg: Any): Option[CanSwim] = {
try {
var res: Option[CanSwim] = None
for (symb <- runtimeMirror(arg.getClass.getClassLoader)
.reflect(arg)
.symbol
.info
.member(TermName("swim")) //get all methods named swim
.asTerm
.alternatives) { //alternatives because it might be overloaded
if (symb.isMethod) {
val msymb = symb.asMethod
//Check if the signature matches (Returns Unit and has 1 empty parameter list)
if (msymb.returnType =:= typeOf[Unit] && msymb.paramLists == List(List()))
res = Some(arg.asInstanceOf[CanSwim])
}
}
res
} catch {
case _ => None
//Might want to change this, but I don't think it's necessary to handle or throw exceptions
//If it failed, it probably means it can't swim
}
}
}
Link to Scastie
However, I really wouldn't recommend it. It's probably just easier to refactor your code.
<script src="https://scastie.scala-lang.org/gFBe7jTQQiW3WnPVTJoFPw.js"></script>

Scala missing parameter type for expanded function The argument types of an anonymous function must be fully known. (SLS 8.5)

I have the following snippet I need to complete for an assignment. To fulfill the asignment I have to correctly replace the comments /*fulfill ...*/. However I tried my best and I am still getting an
missing parameter type for expanded function The argument types of an anonymous function must be fully known. (SLS 8.5) error.
I found similar questions related to this error. However I could not derive a solution for my paticular problem of those answers.
So the target is to check whether the events fulfill the properties.
I am glad for every hint.
This is the code I need to complete:
import scala.collection.mutable.MutableList
abstract class Event
case class Command(cmdName: String) extends Event
case class Succeed(cmdName: String) extends Event
case class Fail(cmdName: String) extends Event
class Property(val name: String, val func: () => Boolean)
class Monitor[T] {
val properties = MutableList.empty[Property]
// (propName: String)(formula: => Boolean) was inserted by me
def property(propName: String)(formula: => Boolean) /* fulfill declaration here */ {
properties += new Property(propName, formula _)
}
var eventsToBeProcessed = List[T]()
def check(events: List[T]) {
for (prop <- properties) {
eventsToBeProcessed = events
println(prop.func())
}
}
def require(func: PartialFunction[T, Boolean]):Boolean = {
/* Fulfill body */
// This is what I came up with and what throws the compilation error
// case event:T => if (func.isDefinedAt(event)) Some(func(event)) else None
// Edit 1: Now I tried this but it prints that properties evaluate to false
var result = true
for (event <- eventsToBeProcessed){
if (func.isDefinedAt(event)){
result = result && func(event)
}
}
return result
}
}
class EventMonitor extends Monitor[Event] {
property("The first command should succeed or fail before it is received again") {
require {
case Command(c) =>
require {
case Succeed(`c`) => true
case Fail(`c`) => true
case Command(`c`) => false
}
}
}
property("The first command should not get two results") {
require {
case Succeed(c) =>
require {
case Succeed(`c`) => false
case Fail(`c`) => false
case Command(`c`) => true
}
case Fail(c) =>
require {
case Succeed(`c`) => false
case Fail(`c`) => false
case Command(`c`) => true
}
}
}
property("The first command should succeed") {
/* Add a property definition here which requires that the first command does not fail.
* It should yield OK with the events listed in the main method.
*/
// This is what I came up with
require{
case Command(c) =>
require{
case Succeed(`c`)=> true
case Fail(`c`) => false
}
}
}
}
object Checker {
def main(args: Array[String]) {
val events = List(
Command("take_picture"),
Command("get_position"),
Succeed("take_picture"),
Fail("take_picture")
)
val monitor = new EventMonitor
monitor.check(events)
// Desired output should be "true false true"
}
}
You wrote require function that returns T => Option[Boolean] intead of Boolean.
You should rewrite it on something like this:
def require(func: PartialFunction[T, Boolean]):Boolean = {
val left = eventsToBeProcessed.dropWhile(!func.isDefinedAt(_))
left.headOption.forall(head => {
eventsToBeProcessed = left.tail
func(head)
})
}

How to make only few datatype which is not related to each other acceptable by generics

There is a trait which works perfectly. However, I would like to refactor the part related to generic [T] in order to limit the data type which could be accepted by generic [T] (I need only Option[JsValue] , JsValue , StringEnumEntry , String ). Is it possible to solve this problem through shapeless coproduct? Maybe there are other solutions?
trait ParameterBinders extends Log {
def jsonBinder[T](json: T, jsonType: java.lang.String = "json"): ParameterBinderWithValue = {
val jsonObject = new PGobject()
jsonObject.setType(jsonType)
json match {
case json: Option[JsValue] =>
jsonObject.setValue(json.map(Json.stringify).orNull)
case json: JsValue =>
jsonObject.setValue(Json.stringify(json))
case json: StringEnumEntry =>
jsonObject.setValue(json.value)
case json: String =>
jsonObject.setValue(json)
case _ =>
logger.error("unexpected data type ")
}
if (jsonType == "JSONSCHEMATYPE" || jsonType == "SYSPROPERTYTYPE") {
ParameterBinder(this, (ps, i) => {
ps.setObject(i, jsonObject)
})
} else {
ParameterBinder(json, (ps, i) => {
ps.setObject(i, jsonObject)
})
}
}
}
The easiest way is to use an ADT as described in the link of the first comment.
If you don't want to change the types that are accepted in jsonBinder then you can solve the problem by using a typeclass.
e.g.
trait JsonBindValue[T] {
def value(t: T): String
}
you would then have to provide instances for your accepted datatypes
object JsonBindValue {
implicit val OptJsBinder = new JsonBindValue[Option[JsValue]] {
def value(t: Option[JsValue]): String = {
t.map(Json.stringify).orNull
}
}
... more instances here
}
finally your function would look like this:
def jsonBinder[T : JsonBindValue](json: T, jsonType: java.lang.String = "json"): ParameterBinderWithValue = {
val binder = implicitly[JsonBindValue[T]]
jsonObject.setType(jsonType)
jsonObject.setValue(binder.value(json))
...
}
if you call the function without a implicit instance in scope you will get a compile time error.

How to patten match on just the class, not the class attributes in Scala?

I have some classes which sometimes have many many attributes, the classes are very large, so I don't want to turn the class into a case class.
However, I still want to be able to do a pattern match on the class type.
What I have been doing is the following:
object CourseSemester {
implicit val courseSemesterCase = (entity: CourseSemester)
=> { CourseSemesterCase(entity) }
case class CourseSemesterCase(entity: CourseSemester)
}
import CourseSemester._
class CourseSemester(val courses: List[Course],
val startDate: EventDate,
val endDate: EventDate,
val createdUpdatedBy: CreatedUpdatedBy,
... there are so many attributes... ) {
def totalCoursesInSemester: Int = courses.length
}
This allows me to do a match on a CourseSemester to the case class, so I can identify the class type in my pattern match. For example:
val c = new CourseSemester(...)
c match {
case CourseSemesterCase(a) => { }
case SomeOtherCase(b) => { }
}
Is this a reasonable way to do it, or is there a better way?
You may use Type Ascription
c match {
case cs : CourseSemester => // use cs
case s : SomeOther => // s is object of SomeOther type
}

Type mismatch when using Scala Trait in Play?

Using the Play! Framework 1.2.4. I've got a nifty trait that checks an API key and HTTPS, but if I want to access the account associated with that key and reference it in my controller, it throws a type mismatch; found : java.lang.Object required: Long
So here's my API controller (incomplete):
object API extends Controller with Squeryl with SecureAPI {
import views.API._
def job(param:String) = {
val Job = models.Job
param match {
case "new" => Job.createFromParams(params,thisAccount) //thisAccount comes from the trait
case "update" =>
case "get" =>
case "list" =>
}
}
}
and the secure trait:
trait SecureAPI {
self:Controller =>
#Before
def checkSecurity(key:String) = {
if(!self.request.secure.booleanValue) {
Redirect("https://" + request.host + request.url);
} else {
models.Account.getByKey(key) match {
case Some(account) => {
renderArgs += "account" -> account.id
Continue
}
case _ => Forbidden("Key is not authorized.")
}
}
}
def thisAccount = renderArgs("account").get
}
How would I properly access thisAccount? Thanks
Your problem is simply that renderArgs is only declared to return an Object from its get call (which is fair enough because it could be just about anything).
Consequently the inferred type of your thisAccount method will be () => Object.
You'll need to cast the returned type into a Long, something like (though perhaps with some error-checking):
def thisAccount = renderArgs("account").get.asInstanceOf[Long]