I have some code where I have a collection of functions. Each function might have 1 or 2 arguments. When iterating through these functions I check whether the element is of type Function1 or Function2. The problem is that I start getting type erasure warnings because I have to define the parameter datatypes in order for it to compile (ex. Function2[String,Int] -- see example warning below+).
I understand that Java strips the parameter type information away when it gets compiled so it can't pattern match the Function2 that I am defining. The thing is, I only want to test if the function is of type Function1 or Function2, and from there I know what data types I need to pass to the function. I tried defining them as ex. Function2[Any,Any] and Function2[Object,Object], but neither of these suppressed the warnings. Is there any way to pattern match against functions of different parameter counts without asking it to also check the parameter types?
[warn] /home/ubuntu/aa-2-0/src/main/scala/hw.scala:818: non-variable type argument Any in type Any => Any is unchecked since it is eliminated by erasure
[warn] else if(col_data.isInstanceOf[Function1[Any,Any]]) mapped_data+= col -> col_data.asInstanceOf[Function1[Any,String]].apply(page)
[warn] ^
[warn] /home/ubuntu/aa-2-0/src/main/scala/hw.scala:819: non-variable type argument Any in type (Any, Any) => Any is unchecked since it is eliminated by erasure
[warn] else if(col_data.isInstanceOf[Function2[Any,Any,Any]]) mapped_data+= col -> col_data.asInstanceOf[Function2[Any,Any,String]].apply(result_row,page)
I know there is reflection and tagtypes and all that, but those seem like ugly and overly elaborate hacks to solve my rather trivial problem. Instead, I was planning to resort to encapsulating these functions in FunctionOne,FunctionTwo case classes then just test for those, but wanted to first see if there was a more elegant solution to be learned.
I wouldn't make assorted lists of different function types, which gives you this problem. But if you must, you can use wildcards:
if(col_data.isInstanceOf[Function1[_,_]])
(You can also use the sugared notation _ => _, (_,_) => _ etc.)
Related
Not really sure the standard terminology here, so I'll try to describe what I'm trying to do. In case you're curious, the app I'm actually trying to write is an asynchronous task queue similar to Resque or rq.
I have a type TaskDef[ArgsT <: AnyVal, ResultT <: AnyVal]. In case you're curious, TaskDef represents "how to execute an asynchronous task which takes argument type ArgsT and result type ResultT, or, the code behind a task".
I'm trying to define a type TaskInst[DefT <: TaskDef]. In case you're curious, TaskInst represents "a TaskDef and associated argument to run it with, or, an actual task instance being submitted to the queue". TaskInst has two members, definition: DefT and arguments whose type I cannot write in code.
In English, my desired constraint is: "For a given DefT, where DefT is some TaskDef[ArgsT, ResultT], TaskInst[DefT] should contain a DefT and an ArgsT". That is, the argument type of the task definition should match the type of the argument given to the task.
How do I express this in the Scala type system?
Alternatively, am I modeling my domain incorrectly and attempting to do something un-idiomatic? Would some alternative approach be more idiomatic?
Thanks in advance!
EDIT:
I think my historical self writing Java would probably have resorted to unchecked casts at this point. This is definitely feasible with some amount of unchecked casts and just leaving out the constraint between the type of the TaskInst's arguments vs the type of the embedded TaskDef's arguments. But, I do wonder whether this is something the compiler can enforce, and hopefully without too scary a syntax.
Define them as abstract types:
trait TaskDef {
type Arguments <: AnyVal
type Result <: AnyVal
}
Then use a type projection:
trait TaskInst[DefT <: TaskDef] {
def definition: DefT
def arguments: DefT#Arguments
}
Live Demo
An add-on to the answer that #rightfold gave:
If you are looking to use type parameters throughout, you will need to properly pass the type parameters through to the type constructors.
Excuse me, that's a bit ambiguous for me to say it that way, so let me use my current code as a concrete example.
trait TaskDef[ArgT_, ResT_] {
type ArgT = ArgT_
type ResT = ResT_
val name: String
def exec(arg: ArgT): String \/ ResT
}
class TaskInst[ArgT, ResT, DefT <: TaskDef[ArgT, ResT]] (
val id: UUID,
val defn: DefT,
val arg: ArgT
)
The main divergence of my current code from #rightfold's example is that TaskDef takes type parameters. Then, when TaskInst's declaration references TaskDef, it must provide appropriate types to the type constructor.
I initially made the mistake of passing in placeholders. That is, I was writing class TaskInst[DefT <: TaskDef[_, _]. Turns out, this doesn't mean what I thought it meant. (I don't know. Perhaps others might be inclined to follow the same line of thought. So, this is just a warning not to.) Don't do that, because then scalac will interpret the expected to mean a generated placeholder (which, as you might imagine, nothing matches), and then you get an obscure error message like the following.
[error] /Users/mingp/Code/scala-redis-queue/src/main/scala/io/mingp/srq/core/TaskInst.scala:8: type mismatch;
[error] found : TaskInst.this.arg.type (with underlying type _$1)
[error] required: _$1
[error] val arg: DefT#ArgT_
[error] ^
[error] one error found
Just posting this in hopes that future readers don't fall into the same hole I did.
EDIT:
As a further addendum, now that I've tried it out for a day, my impression is that this isn't actually a good data model for asynchronous tasks. You're better off combining, since stand-alone instances of TaskDef aren't really useful.
Consider the following type:
case class Subscriber(books: List[String])
And its instance wrapped in an option:
val s = Option(Subscriber(List("one", "two", "three")))
And an attempt to println all books for a subscriber:
s.flatMap(_.books).foreach(println(_))
This fails, due to:
Error: type mismatch;
found : List[String]
required: Option[?]
result.flatMap(_.books).foreach(println(_))
^
This is kind of expected, because flatMap must return types compatible to its source object and one can easily avoid this error by doing:
s.toList.flatMap(_.books).foreach(println(_))
I could also avoid flatMap, but its not the point.
But isn't there some smart method of achieving this without explicit toList conversion? Intuitively, None and List.empty have a lot in common. And during compilation of s.flatMap, s is implicitly converted to Traversable.
Something in scalaz, maybe?
I think smart implementation of flatamap is a bit missleading.
Such an implementation, as flatmap is well defined, would break the monadic behavior one expects when using flatmap and be in fact broken.
The problem with the smart method is
How should the compiler know what kind of type to use.
How should it be possible to infer if you wanted a List[_] or and Option[_] as a result?
What to do with other types, unknown types and what kind of conversion to apply on them ?
You could achieve the same result you would with the .list in that way , because for given example types don't matter (except you are aiming for a list of Units) at all as there is just output as a side effect:
s foreach ( _.books foreach println )
A direction to go, might be an implicit conversion using structural types but you would get a performance penalty.
The smarter way to do that would be is by using map.
val s = Option(Subscriber(List("one", "two", "three")))
s.map(_.books.map(println))
foreach has side effects while map doesn't
I'm working on a mapper and wanted a typesafe way to capture class fieldnames for mapping and went with a syntax I'd used in C#:
case class Person(name: String, age: Int)
new Mapping[Person]() {
field(_.age).name("person_age").colType[java.lang.Integer]
field(_.name).name("person_name")
}
where def field(m: T => Unit): FieldMap
This triggers the following warnings:
Warning:(97, 13) a pure expression does nothing in statement position; you may be omitting necessary parentheses
field(_.age).name("person_age").colType[java.lang.Integer]
^
Warning:(98, 13) a pure expression does nothing in statement position; you may be omitting necessary parentheses
field(_.name).name("person_name")
^
So clearly that's not a desirable syntax. Any way I can tweak the signature of field to avoid the warning or is there a more idiomatic scala way of mapping fields in a typesafe manner?
Note: #sjrd's answer indeed gets rid of the warning, but the attempted feature doesn't seem feasible with scala reflection after all. My end goal is a Mapper that allows the specifying of T members in a compile time checked mannner, rather than strings, so it's less vulnerable to typo's and refactoring issues.
The field method takes a T => Unit function as parameter. Hence, the lambda _.age, which is equivalent to x => x.age, is typechecked as returning Unit. The compiler warns that you are using a pure expression (x.age) in statement position (expected type Unit), which basically means that the expression is useless, and might as well be removed.
There is a very simple symptomatic solution to your problem: replace m: T => Unit by m: T => Any. Now your expression x.age is not in statement position anymore, and the compiler is happy.
But your code suggests that there is something wrong a little bit deeper, since you obviously don't use the result of m anywhere. Why is m for anyway?
I am trying to understand how to think about type classes in Haskell versus traits in Scala.
My understanding is that type classes are primarily important at compile time in Haskell and not at runtime anymore, on the other hand traits in Scala are important both at compile time and run time. I want to illustrate this idea with a simple example, and I want to know if this viewpoint of mine is correct or not.
First, let us consider type classes in Haskell:
Let's take a simple example. The type class Eq.
For example, Int and Char are both instances of Eq. So it is possible to create a polymorphic List that is also an instance of Eq and can either contain Ints or Chars but not both in the same List.
My question is : is this the only reason why type classes exist in Haskell?
The same question in other words:
Type classes enable to create polymorphic types ( in this example a polymorphic List) that support operations that are defined in a given type class ( in this example the operation == defined in the type class Eq) but that is their only reason for existence, according to my understanding. Is this understanding of mine correct?
Is there any other reason why type classes exist in ( standard ) Haskell?
Is there any other use case in which type classes are useful in standard Haskell ? I cannot seem to find any.
Since Haskell's Lists are homogeneous, it is not possible to put Char and Int into the same list. So the usefulness of type classes, according to my understanding, is exhausted at compile time. Is this understanding of mine correct?
Now, let's consider the analogous List example in Scala:
Lets define a trait Eq with an equals method on it.
Now let's make Char and Int implement the trait Eq.
Now it is possible to create a List[Eq] in Scala that accepts both Chars and Ints into the same List ( Note that this - putting different type of elements into the same List - is not possible Haskell, at least not in standard Haskell 98 without extensions)!
In the case of the Haskell's List, the existence of type classes is important/useful only for type checking at compile time, according to my understanding.
In contrast, the existence of traits in Scala is important both at compile time for type checking and at run type for polymorphic dispatch on the actual runtime type of the object in the List when comparing two Lists for equality.
So, based on this simple example, I came to the conclusion that in Haskell type classes are primarily important/used at compilation time, in contrast, Scala's traits are important/used both at compile time and run time.
Is this conclusion of mine correct?
If not, why not ?
EDIT:
Scala code in response to n.m.'s comments:
case class MyInt(i:Int) {
override def equals(b:Any)= i == b.asInstanceOf[MyInt].i
}
case class MyChar(c:Char) {
override def equals(a:Any)= c==a.asInstanceOf[MyChar].c
}
object Test {
def main(args: Array[String]) {
val l1 = List(MyInt(1), MyInt(2), MyChar('a'), MyChar('b'))
val l2 = List(MyInt(1), MyInt(2), MyChar('a'), MyChar('b'))
val l3 = List(MyInt(1), MyInt(2), MyChar('a'), MyChar('c'))
println(l1==l1)
println(l1==l3)
}
}
This prints:
true
false
I will comment on the Haskell side.
Type classes bring restricted polymorphism in Haskell, wherein a type variable a can still be quantified universally, but ranges over only a subset of all the types -- namely, the types for which an instance of the type class is available.
Why restricted polymorphism is useful? A nice example would be the equality operator
(==) :: ?????
What its type should be? Intuitively, it takes two values of the same type and returns a boolean, so:
(==) :: a -> a -> Bool -- (1)
But the typing above is not entirely honest, since it allows one to apply == to any type a, including function types!
(\x :: Integer -> x + x) == (\x :: Integer -> 2*x)
The above would pass type checking if (1) were the typing for (==), since both arguments are of the same type a = (Integer -> Integer). However, we can not effectively compare two functions: well-known Computability results tell us that there is no algorithm to do that in general.
So, what we could do to implement (==)?
Option 1: at run time, if a function (or any other value involving functions -- such as a list of functions) is found to be passed to (==), raise an exception. This is what e.g. ML does. Typed programs can now "go wrong", despite checking types at compile time.
Option 2: introduce a new kind of polymorphism, restricting a to the function-free types. For instance, ww could have (==) :: forall-non-fun a. a -> a -> Bool so that comparing functions yields to a type error. Haskell exploits type classes to obtain exactly that.
So, Haskell type classes allow one to type (==) "honestly", ensuring no error at run time, and without being overly restrictive. Of course, the power of type classes goes far beyond of that but, at least in my own view, they primary purpose is to allow restricted polymorphism, in a very general and flexible way. Indeed, with type classes the programmer can define their own restrictions on the universal type quantifications.
Given a java class with two methods (taken from mockito):
OngoingStubbing<T> thenReturn(T value);
OngoingStubbing<T> thenReturn(T value, T... values);
If I invoke from scala with
....thenReturn("something")
I get an error:
Description Resource Path Location Type
ambiguous reference to overloaded definition, both method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object, x$2: <repeated...>[java.lang.Object])org.mockito.stubbing.OngoingStubbing[java.lang.Object] and method thenReturn in trait OngoingStubbing of type (x$1: java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object] match argument types (java.lang.String)
And I cannot figure out how to fix this.
This is a known Scala-Java interoperability problem, though it's unfortunately not in the FAQ. Here's the Scala ticket describing the problem. Essentially, both methods are applicable when you give a single argument, and the Scala compiler currently doesn't have any heuristic to decide which one is "more specific". Alexey Romanov's approach to always use the varargs version is a good workaround:
thenReturn("something", Nil: _*)
There is also a question running into a similar problem with JCommander. One of the answers there gives a clever workaround using structural types. This approach will use reflection behind the scenes, so you may or may not want to go that direction. For your use case, it would look something like:
type useSingleArgVersion = { def thenReturn(value: AnyRef): OngoingStubbing }
(...).asInstanceOf[useSingleArgVersion].thenReturn("something")
Finally, there is a similar question running into a similar problem with mokito. It doesn't really provide any workarounds, but it does describe the problem in a bit more detail, if you're interested in the reason this happens.
If calling the vararg version is acceptable,
thenReturn("something", Nil: _*)
Can't think of a way to call the method without varargs right now.
These answers are all to the wrong question. The difference is subtle, but this is not the same issue as the one in the linked ticket. That one does require unreasonable gymnastics to call the non-varargs method. For this one, the following is enough.
thenReturn[String]("something")
Or, if you didn't want to do that for some reason, you don't need the type alias and the cast. You can use a structural type ascription directly.
(this: { def thenReturn[T](s: T): OngoingStubbing[T] }).thenReturn("something")
The issue here is type inference at the intersection of overloading and polymorphism - one method is more specific, but scalac doesn't figure out which. The issue in SI-2991 is genuine ambiguity due to an interaction between overloading and tuple conversion - neither is more specific.
Assuming others will find this question when having the overloaded method value thenReturn with alternatives error, I want to share my solution as well.
Instead of
when(field.getValue(isA(classOf[Record]))).thenReturn(value)
I use
doReturn(value).when(field).getValue(isA(classOf[Record]))
which resolves the disambiguity in my case.
The workaround is quite easy:
OngoingStubbing<T> thenReturn(T value);
OngoingStubbing<T> thenReturn(T value1, T valu2, T... values);
There is no "varargs must be non empty" feature.
I tried Steve's solution and got a huge compiler error including:
scala.tools.nsc.symtab.Types$TypeError: type mismatch;
found : scala.reflect.Manifest[Nothing]
required: scala.reflect.ClassManifest[B]
Note: Nothing <: B, but trait ClassManifest is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: B`. (SLS 3.2.10)
I was able to make it work with something like:
thenReturn("something", Seq.empty[Object]: _*)