I'm having trouble defining a method using generic parameters in Scala.
Let's say I want a something like this:
class CollectionConverter {
def convertListToSet(list: java.util.List[SomeType]): java.util.Set[SomeType] = {
val s = new java.util.HashSet[SomeType]
s.addAll(list)
s
}
}
I can't seem to find a way to make Scala understand that I don't know what SomeType is, just that whatever it is, the returned generic set will have the same generic type as the supplied list. It complains that I haven't defined SomeType. But that's the thing -- I don't know or care what SomeType is, it could be called YeahYeahYeah for all I care.
I don't want to use List[Any], and List[_] creates other problems, so... what's the right way to do this?
Any help would be greatly appreciated!
That's what type parameters for methods are for.
def convertListToSet[SomeType](list: java.util.List[SomeType]): java.util.Set[SomeType] = {
val s = new java.util.HashSet[SomeType]
s.addAll(list)
s
}
Related
I have a following question. Our project has a lot of code, that runs tests in Scala. And there is a lot of code, that fills the fields like this:
production.setProduct(new Product)
production.getProduct.setUuid("b1253a77-0585-291f-57a4-53319e897866")
production.setSubProduct(new SubProduct)
production.getSubProduct.setUuid("89a877fa-ddb3-3009-bb24-735ba9f7281c")
Eventually, I grew tired from this code, since all those fields are actually subclasses of the basic class that has the uuid field, so, after thinking a while, I wrote the auxiliary function like this:
def createUuid[T <: GenericEntity](uuid: String)(implicit m : Manifest[T]) : T = {
val constructor = m.runtimeClass.getConstructors()(0)
val instance = constructor.newInstance().asInstanceOf[T]
instance.setUuid(uuid)
instance
}
Now, my code got two times shorter, since now I can write something like this:
production.setProduct(createUuid[Product]("b1253a77-0585-291f-57a4-53319e897866"))
production.setSubProduct(createUuid[SubProduct]("89a877fa-ddb3-3009-bb24-735ba9f7281c"))
That's good, but I am wondering, if I could somehow implement the function createUuid so the last bit would like this:
// Is that really possible?
production.setProduct(createUuid("b1253a77-0585-291f-57a4-53319e897866"))
production.setSubProduct(createUuid("89a877fa-ddb3-3009-bb24-735ba9f7281c"))
Can scala compiler guess, that setProduct expects not just a generic entity, but actually something like Product (or it's subclass)? Or there is no way in Scala to implement this even shorter?
Scala compiler won't infer/propagate the type outside-in. You could however create implicit conversions like:
implicit def stringToSubProduct(uuid: String): SubProduct = {
val n = new SubProduct
n.setUuid(uuid)
n
}
and then just call
production.setSubProduct("89a877fa-ddb3-3009-bb24-735ba9f7281c")
and the compiler will automatically use the stringToSubProduct because it has applicable types on the input and output.
Update: To have the code better organized I suggest wrapping the implicit defs to a companion object, like:
case class EntityUUID(uuid: String) {
uuid.matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}") // possible uuid format check
}
case object EntityUUID {
implicit def toProduct(e: EntityUUID): Product = {
val p = new Product
p.setUuid(e.uuid)
p
}
implicit def toSubProduct(e: EntityUUID): SubProduct = {
val p = new SubProduct
p.setUuid(e.uuid)
p
}
}
and then you'd do
production.setProduct(EntityUUID("b1253a77-0585-291f-57a4-53319e897866"))
so anyone reading this could have an intuition where to find the conversion implementation.
Regarding your comment about some generic approach (having 30 types), I won't say it's not possible, but I just do not see how to do it. The reflection you used bypasses the type system. If all the 30 cases are the same piece of code, maybe you should reconsider your object design. Now you can still implement the 30 implicit defs by calling some method that uses reflection similar what you have provided. But you will have the option to change it in the future on just this one (30) place(s).
Suppose I have a function defined in the following way:
def fun[T](somevar: SomeType[T]) = {
// some action
}
Is there a way to git rid of type parameter [T] and just use it as
def fun(somevar: SomeType[T]) = {
// some action
}
I mean, the type information should already be available inside someVar, no? Why not use them somehow?
The purpose of your question is unclear.
The users of your function (the client code) don't need to worry about the type parameter. They can just call fun(myvar).
If the type T is immaterial to the body of fun() then it can be dropped: SomeType[_]
But if T is meaningful to the workings of the function then the compiler has to be told that it is a type parameter. Just seeing this, SomeType[T], the compiler can't infer that T is now a type parameter. It will, instead, look for a definition of T outside of fun() and, not finding it, will throw an error.
This would be problematic because what you're removing was never actually redundant. When the function is defined as def fun[T](...), T is defined as a new type variable. Otherwise, it refers to a type or type variable defined somewhere else. You seem to think that
def fun(somevar: SomeType[T]) { ... }
should mean that T is a new type variable. Is that always the case, though? Not in this code:
trait T { ... }
def fun(somevar: SomeType[T]) { ... }
So where do we go from there? Define new type variables whenever a type name is referred to that hasn't been defined before? That would turn the following compile-time errors truly weird. (Or worse, sometimes allow them to compile?)
def fun(somevar: SomeType[Integr]) { ... }
class C[Thing] {
def g(x: List[Think]) = ...
}
For the compile-time type-checking philosophy of Scala, that way lies madness.
Unless you want T to be a specific type, no, there is not. The method signature wouldn't be valid without it. What somevar knows is irrelevant.
You can't do this. Compiler needs to know what is type T. If you don't care about SomeType type parameter, you can use this form:
def fun(somevar: SomeType[_]) = {
// some action
}
Let's say I have a case class
case class Foo[T<:Bar[T]](t:T)
And I have a
case class FooWrapper[T<:Bar[T]](foos:Seq[Foo[T]])
So far, so good.
Unfortunately, I now want to merge two FooWrapprs in an environment where I have no access to the T used to construct them. I.e. attempting something like this:
def merge(fw1:FooWrapper,fw2:FooWrapper) = {
FooWrapper(fw1.foos ++ fw2.foos)
}
Obviously, the T used to construct fw1,fw2 could be different, which is why this merge fails.
Perhaps I'm just too tired to see the obvious, but what would be the proper way to overcome this limitation? Would having the wrapper class itself implement a merge method work or can I forget about that due to type erasure?
EDIT
I would like a merge method like this:
case class FooWrapper[T<:Bar[T]](foos:Seq[Foo[T]]){
def merge(other:FooWrapper[T]) = FooWrapper[T](this.foos ++ other.foos)
}
And then
def doSomethingWith(w1:FooWrapper,w2:FooWrapper) ={
w1.merge(w2)
}
This compiles fine and just might work, but I'm not sure I can rely on its working correctly.
You can enforce the equivalence of the types of the fw1 and fw2 like this:
def merge[T](fw1:FooWrapper[T],fw2:FooWrapper[T]) = {
FooWrapper[T](fw1.foos ++ fw2.foos)
}
Otherwise, please specify what type do you expect as the result of the merge method?
I'm trying to define a method which is generic both in its parameter and return type. Basically to make a helper function for JSON serialization to/from case classes.
so I want to write something like this pseudocode:
def post[Request,Response](data:Request) : Response = ???
case class A(i:String)
case class B(j:Int)
val result = post[A,B]("input")
in this case (assuming no errors) result is of type B.
It's understandable that the compiler can't infer the return value, but I'd like it to infer the Request type. In other words I'd like to write something like
val result = post[B]("input")
where the type of A is inferred by the data parameter, so the user need only specify the return type when calling the function.
I don't know many details of Scala specifically, but in Haskell that ability is enabled by a compiler option called "Functional dependencies", whereby you have a typeclass with two type variables, one of which can be derived from the other - see section 7.4.3 of http://www.haskell.org/ghc/docs/6.6/html/users_guide/type-extensions.html. Obviously you can't just use this feature, since it's in a different language, but knowing what it's called should help you find a solution. For example, Functional dependencies in Scala looks like a good guess; although again, I don't know enough Scala to read that article and then tell you exactly how to answer your original JSON question.
Following on from #amalloy's answer, and the link he provides, the Scala equivalent for what you are trying to achieve would be something like the following:
trait ReqResp[Request,Response] {
def apply(req: Request): Response
}
def post[Request,Response](data:Request)(implicit rr: ReqResp[Request,Response]): Response = rr(data)
case class A(i:String)
case class B(j:Int)
implicit object reqRespAB extends ReqResp[A,B] {
def apply(a: A) = B(a.i.toInt)
}
val result = post(A("456"))
This gives the output:
result: B = B(456)
I'd like to write a type alias to shorten, nice and encapsulated Scala code.
Suppose I got some collection which has the property of being a list of maps, the value of which are tuples.
My type would write something like List[Map[Int, (String, String)]], or anything more generic as my application allows it. I could imagine having a supertype asking for a Seq[MapLike[Int, Any]] or whatever floats my boat, with concrete subclasses being more specific.
I'd then want to write an alias for this long type.
class ConcreteClass {
type DataType = List[Map[Int, (String, String)]]
...
}
I would then happily use ConcreteClass#DataType everywhere I can take one, and use it.
Now suppose I add a function
def foo(a : DataType) { ... }
And I want to call it from outside with an empty list.
I can call foo(List()), but when I want to change my underlying type to be another type of Seq, I'll have to come back and change this code too. Besides, it's not very explicit this empty list is intended as a DataType. And the companion object does not have the associated List methods, so I can't call DataType(), or DataType.empty. It's gonna be even more annoying when I need non-empty lists since I'll have to write out a significant part of this long type.
Is there any way I can ask Scala to understand my type as the same thing, including companion object with its creator methods, in the interest of shortening code and blackboxing it ?
Or, any reason why I should not be doing this in the first place ?
The answer was actually quite simple:
class ConcreteClass {
type DataType = List[String]
}
object ConcreteClass {
val DataType = List
}
val d = ConcreteClass.DataType.empty
This enables my code to call ConcreteClass.DataType to construct lists with all the methods in List and little effort.
Thanks a lot to Oleg for the insight. His answer is also best in case you want not to delegate to List any call to ConcreteClass.DataType, but control precisely what you want to allow callers to do.
What about this?
class ConcreteClass {
type DataType = List[String]
}
object DataType {
def apply(): ConcreteClass#DataType = Nil
}
//...
val a = DataType()