I want Map to be implicit converted to java.utils.Properties.
implicit def map2Properties(map: Map[String, String]): Properties =
map.foldLeft(new java.util.Properties) { case (p, (k, v)) => p.put(k, v); p }
val properties :Properties = Option(Map[String,String]("k"->"v")).getOrElse(Map[String, String]())
Error:(7, 82) type mismatch;
found : Object
required: java.util.Properties
I got Map[String,String]() being converted first, so I got Object type in return.
Why not it to convert the both Map in Option and orElse together or convert the expression lazily in the end ?
How can I do to get it return Properties approprietly?
I am not exactly sure why the scala compiler cannot find the conversion for your Map. But I suspect it has something to do with (maybe) erasure and the signature of Option.getOrElse:
def getOrElse[B >: A](default: => B): B
The result is not necessarily the same type as the original option because it could also be a super type like Map[Any, Any].
There are several options how to work around this limitation:
Tell the compiler the result type of getOrElse explicitly:
val properties2: Properties = Option(Map[String,String](("k","v"))).getOrElse(Map.empty[String, String]): Map[String, String]
Use an intermediate step to tell the compiler that the option should contain Properties:
val propOpt: Option[Properties] = Option(Map[String,String](("k","v")))
val properties3: Properties = propOpt.getOrElse(Map.empty[String, String])
// or
val properties4: Properties = (Option(Map[String,String](("k","v"))): Option[Properties]).getOrElse(Map.empty[String, String])
// OR, shortest so far:
val properties5: Properties = Option(Map[String,String](("k","v")): Properties).getOrElse(Map.empty[String, String])
Something weird is going on with implicit conversion and return type of getOrElse.
However, this works:
Option(Map[String,String](("k","v"))).fold(Map[String,String]())(identity)
and so does this
Option(Map[String,String](("k","v"))).getOrElse[Map[String,String]](Map())
Related
How to create an implicit converter so this code
case class Cookie(name: String, value: String)
val cookies: Seq[Cookie] = ???
val cookieMap: Map[String, String] = cookies.toMap
wil work? How to define implicit ev: A <:< (K, V)?
You can just do:
cookies.iterator.map(c => c.name -> c.value).toMap
To do the conversion in a single iteration. You may even hide that behind an extension method or something if you please.
Or you can provide an
implicit def Cookie2Tuple2(c: Cookie): (String, String) = c.name -> c.value
But that may blow up in other unexpected parts of the code.
I personally would define my own.
final case class Cookie(underlying: List[Cookie]) {
def toMap: Map[String, String] =
underlying.iterator.map(c => c.name -> c.value).toMap
}
From scala doc:
An instance of A <:< B witnesses that A is a subtype of B. Requiring
an implicit argument of the type A <:< B encodes the generalized
constraint A <: B.
That means that evidence Cookie <:< (K, V) means Cookie must be a subclass of (K,V). But it's not possible as tuple cannot be subclassed. Also, note that evidence are not implicit conversions, there are used to get guaranty at compile time but are not "applied".
(you can also read: https://stackoverflow.com/a/3427759/1206998)
Also, you can look at the implementation of toMap in IterableOnce
def toMap[K, V](implicit ev: A <:< (K, V)): immutable.Map[K, V] =
immutable.Map.from(this.asInstanceOf[IterableOnce[(K, V)]])
As you can see, it cast the iterable to an iterableOnce of tuple, no conversion of the collection's item is performed. Thus, entries should be effectively (K,V)
So the only thing you can do is add an implicit conversion from Seq[Cookie] to Map(String, String]
import scala.collection.breakOut // to directly convert to Map
case class Cookie(name: String, value: String)
implicit class Cookies(cookies: Seq[Cookie]) {
// use a self descriptive name, to avoid confusion
def toNameValueMap: Map[String, String] = {
cookies.map(c => (c.name, c.value))(breakout)
}
}
// example of use
val cookies: Seq[Cookie] = List(Cookie("chocolate", "good"), Cookie("hazelnut", "better"))
val cookieMap: Map[String, String] = cookies.toNameValueMap
And for the fun of it, here is the generic conversion method that correspond to what you expected toMap to be able to do:
implicit class SeqConversion[A](seq: Seq[A]) {
def convertToMap[K,V](getKey: A => K, getValue: A => V): Map[K,V] ={
seq.map(a => (getKey(a), getValue(a)))(breakOut)
}
}
cookies.convertToMap(_.name, _.value)
The title is attempting to describe the following subtyping
implicitly[Map[Int, String] <:< Iterable[(Int, String)]]
Type parameter A is inferred to (Int, String) here
def foo[A](cc: Iterable[A]): A = cc.head
lazy val e: (Int, String) = foo(Map.empty[Int, String])
however attempting to achieve similar effect using type parameter bounds the best I can do is explicitly specifying arity of the type constructor like so
def foo[F[x,y] <: Iterable[(x,y)], A, B](cc: F[A, B]): (A, B) = cc.head
lazy val e: (Int, String) = foo(Map.empty[Int, String])
because the following errors
def foo[F[x] <: Iterable[x], A](cc: F[A]) = cc.head
lazy val e: (Int, String) = foo(Map.empty[Int, String])
// type mismatch;
// [error] found : A
// [error] required: (Int, String)
// [error] lazy val e: (Int, String) = foo(Map.empty[Int, String])
// [error] ^
Hence using Iterable as upper bound it seems we need one signature to handle unary type constructors Seq and Set, and a separate signature to handle 2-arity type constructor Map
def foo[F[x] <: Iterable[x], A](cc: F[A]): A // When F is Seq or Set
def foo[F[x,y] <: Iterable[(x,y)], A, B](cc: F[A, B]): (A, B) // When F is Map
Is there a way to have a single signature using type bounds that works for all three? Putting it differently, how could we write, say, an extension method that works across all collections?
I think the issue here is that F is set to Map, and kindness is wrong. You would have to have say: I have some type X, that extends F[A], so that when I upcast it, I can use it as F[A] - which in turn we want to be a subtype of Iterable[A]. If we ask about it this way, it sounds hard.
Which is why I personally would just stay at:
# def foo[A](x: Iterable[A]): A = x.head
defined function foo
# foo(List(1 -> "test"))
res24: (Int, String) = (1, "test")
# foo(Map(1 -> "test"))
res25: (Int, String) = (1, "test")
"Give me any x that is an instance of Iterable[A] for A".
If I had to do some derivation... I would probably also go this way. I think this limitation is the reason CanBuildFrom works the way it works - providing matching for part of the type is hard, especially in cases like Map, so let's provide a whole type at once as a parameter, to limit the number of inference needed.
I'm trying to write a function
def convert(x: String): String = ...
that converts its argument by looking up in a map, and returning x if the argument isn't a key in the map. Unfortunately, the map must be obtained by calling a Java method that returns a raw Map:
public static Map getMapFromConfiguration() { ... }
This is legacy code I can't do anything about. In this particular case, the keys and values of the returned map will be String (and it's OK if the code throws an exception if the keys or values have some other type). So far, the only way I've been able to get the code to compile is by constructing a new Map[String,String]:
def convert(x: String): String = {
val mapFromConfig: scala.collection.mutable.Map[_,_] = JavaClass.getMapFromConfiguration().asScala
val convertedMap: Map[String,String] = (mapFromConfig map {
case (key, value) => key.asInstanceOf[String] -> value.asInstanceOf[String] }).toMap
convertedMap.getOrElse(x, x)
}
I've tried various ways to use get or getOrElse directly on mapFromConfig, but haven't found anything that compiles. Some attempts:
val mapFromConfig: scala.collection.mutable.Map[_ <: Any, _ <: Any] = JavaClass.getMapFromConfiguration().asScala
mapFromConfig.getOrElse(x, x).asInstanceOf[String]
Type mismtach, expected: _$1, actual: String
val mapFromConfig: scala.collection.mutable.Map[Any,Any] = JavaClass.getMapFromConfiguration().asScala
mapFromConfig.getOrElse(x, x).asInstanceOf[String]
error: type mismatch;
found : scala.collection.mutable.Map[?0,?1] where type ?1, type ?0
required: scala.collection.mutable.Map[Any,Any]
Note: ?0 <: Any, but trait Map is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
Note: ?1 <: Any, but trait Map is invariant in type B.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
val mapFromConfig: java.util.Map[_,_] = JavaClass.getMapFromConfiguration()
mapFromConfig.getOrDefault(x, x).asInstanceOf[String]
Type mismtach, expected: _$2, actual: String
Is there a good way to accomplish what I need without creating an intermediate map?
The main trick is to cast a non-generic Map to explicitly generic java.util.Map[String, String]. Code that works for me is
val map: java.util.Map[String, String] = ScalaToJava.getMapFromConfiguration.asInstanceOf[java.util.Map[String, String]]
println(map.get("key"))
Given Java code:
public class ScalaToJava {
static Map getMapFromConfiguration() {
HashMap map = new HashMap();
map.put("key", "value");
return map;
}
}
Or if you want to convert map to the Scala one, you can use something like
val map = ScalaToJava.getMapFromConfiguration.asInstanceOf[java.util.Map[String, String]].asScala
println(map.get("key"))
I want to use a map of varying types on an unknown A:
val map: Map[Foo[A], Bar[A]] = ...
...
val foo = new Foo[Qux]
val bar: Bar[Qux] = map(foo)
This doesn't work, because A is an unknown. I have to define it instead as:
val map: Map[Foo[_], Bar[_]] = ...
...
val foo = new Foo[Qux]
val bar: Bar[Qux] = map(foo).asInstanceOf[Bar[Qux]]
This works, but the cast is ugly. I'd rather find a better way. I gather the answer is to use existential types with the forSome keyword, but I'm confused as to how that works. Should it be:
Map[Foo[A], Bar[A]] forSome { type A }
or:
Map[Foo[A] forSome { type A }, Bar[A]]
or:
Map[Foo[A forSome { type A }], Bar[A]]
Actually, none of these work.
Map[Foo[A], Bar[A]] forSome { type A }
is a Map where all keys are of the same type Foo[A] and values of type Bar[A] (but the type A may be different for different maps of this type); in second and third examples, A in Bar[A] is completely different from A under forSome.
This ugly workaround should work:
// need type members, so can't use tuples
case class Pair[A, B](a: A, b: B) {
type T1 = A
type T2 = B
}
type PairedMap[P <: Pair[_, _]] = Map[P#T1, P#T2]
type FooBarPair[A] = Pair[Foo[A], Bar[A]]
val map: PairedMap[FooBarPair[_]] = ...
I want to use a map of varying types on an unknown A
So, you want a variant of Map[K,V] with following interface, correct?
trait DependentMap[K[_],V[_]] {
def add[A](key: K[A], value: V[A]): DependentMap[K,V]
def get[A](key: K[A]): Option[V[A]]
}
Whether it is or not might be a bit hard to tell from the type signature, so let's create a few dummy values and see if the type checker accepts what we want it to accept and rejects what we want it to reject.
// dummy definitions just to check that the types are correct
case class Foo[+A](a: A)
case class Bar[+A](a: A)
val myMap: DependentMap[Foo,Bar] = null
myMap.add(Foo( 42), Bar( 43)) // typechecks
myMap.add(Foo("foo"), Bar("bar")) // typechecks
myMap.add(Foo( 42), Bar("bar")) // type mismatch
val r1: Option[Bar[ Int]] = myMap.get(Foo( 42)) // typechecks
val r2: Option[Bar[String]] = myMap.get(Foo("foo")) // typechecks
val r3: Option[Bar[String]] = myMap.get(Foo( 42)) // type mismatch
So far so good. But look what happens once we start to play with inheritance:
val fooInt: Foo[Int] = Foo(42)
val fooAny: Foo[Any] = fooInt
val barStr: Bar[String] = Bar("bar")
val barAny: Bar[Any] = barStr
println(fooInt == fooAny) // true
myMap.add(fooAny, barAny).get(fooInt) // Bar("bar")?
Since fooInt and fooAny are the same value, we'd naïvely expect this get to succeed. According to the type signature of get, it would have to succeed with a value of type Bar[Int], but where would this value come from? The value we put in has the type Bar[Any] and also the type Bar[String], but certainly not the type Bar[Int]!
Here's another surprising case.
val fooListInt: Foo[List[Int]] = Foo(List[Int]())
val fooListStr: Foo[List[String]] = Foo(List[String]())
println(fooListInt == fooListStr) // true!
myMap.add(fooListInt, Bar(List(42))).get(fooListStr) // Bar(List(42))?
This time fooListInt and fooListStr look like they should be distinct, but in fact they both have the value Nil, of type List[Nothing], which is a subtype of both List[Int] and List[String]. So if we want to mimic the behaviour of Map[K,V] on such a key, get would again have to succeed, but it can't since we gave it a Bar[List[Int]] and it needs to produce a Bar[List[String]].
All this to say, our DependentMap should not consider keys to be equal unless the type A given to add is also equal to the type A given to get. Here is an implementation which uses type tags to ensure that this is the case.
import scala.reflect.runtime.universe._
class DependentMap[K[_],V[_]](
inner: Map[
(TypeTag[_], Any),
Any
] = Map()
) {
def add[A](
key: K[A], value: V[A]
)(
implicit tt: TypeTag[A]
): DependentMap[K,V] = {
val realKey: (TypeTag[_], Any) = (tt, key)
new DependentMap(inner + ((realKey, value)))
}
def get[A](key: K[A])(implicit tt: TypeTag[A]): Option[V[A]] = {
val realKey: (TypeTag[_], Any) = (tt, key)
inner.get(realKey).map(_.asInstanceOf[V[A]])
}
}
And here are a few examples demonstrating that it works as expected.
scala> val myMap: DependentMap[Foo,Bar] = new DependentMap
scala> myMap.add(Foo(42), Bar(43)).get(Foo(42))
res0: Option[Bar[Int]] = Some(Bar(43))
scala> myMap.add(Foo("foo"), Bar("bar")).get(Foo("foo"))
res1: Option[Bar[String]] = Some(Bar(bar))
scala> myMap.add(Foo(42), Bar("bar")).get(Foo(42))
error: type mismatch;
scala> myMap.add[Any](Foo(42), Bar("bar")).get(Foo(42))
res2: Option[Bar[Int]] = None
scala> myMap.add[Any](Foo(42), Bar("bar")).get[Any](Foo(42))
res3: Option[Bar[Any]] = Some(Bar(bar))
scala> myMap.add(Foo(List[Int]()), Bar(List(43))).get(Foo(List[Int]()))
res4: Option[Bar[List[Int]]] = Some(Bar(List(43)))
scala> myMap.add(Foo(List[Int]()), Bar(List(43))).get(Foo(List[String]()))
res5: Option[Bar[List[String]]] = None
This works, but the cast is ugly. I'd rather find a better way.
Then you're probably disappointed that my get is implemented using a cast. Let me try to convince you that there is no other way.
Instead of a map which may or may not contain our key, let's consider a much simpler case.
def safeCast[A,B](
value: A
)(
implicit tt1: TypeTag[A], tt2: TypeTag[B]
): Option[B] = {
if (tt1 == tt2)
Some(value.asInstanceOf[B])
else
None
}
Given a type tag for A and a type tag for B, if the two type tags are equal, then we know that A and B are the same type, and therefore the typecast is safe. But how could we possibly implement this without a typecast? The equality check returns a mere boolean, not a witness of equality like in some other languages. Therefore there is nothing which statically distinguishes the two branches of the if and the compiler cannot possibly know that a cast-free conversion is legal in the "true" branch but illegal in the other.
In the more complicated case of our DependentMap, we also have to compare our type tag with the one we stored when we did an add, and so we also have to use a cast.
I gather the answer is to use existential types with the forSome keyword
I can see why you'd think so. You want a bunch of associations from key to value, where each (key, value) pair has the type (Foo[A], Bar[A]) forSome {type A}. And indeed, if you were not concerned with performance, you could store those associations in a list:
val myList: List[(Foo[A], Bar[A]) forSome {type A}]
Since the forSome is inside the brackets, this allows each entry in the list to use a different A. And since Foo[A] and Bar[A] are both to the left of the forSome, in each entry the As must match.
In the case of Map, however, there is no place to put the forSome to obtain the result you want. The problem with Map is that it has two type parameters, which prevents us from from putting them both to the left of the forSome without putting the forSome outside of the brackets. It wouldn't make sense to do so: since the two type parameters are independent, there is nothing which links one occurrence of the left type parameter to a corresponding occurrence of the right type parameter, and so there is no way to know which As should match. Consider the following counter-example:
case class NotMap[K,V](k1: K, k2: K, v1: V, v2: V, v3: V)
There isn't the same number of K values as there are V values, so in particular there is no correspondence between the K values and the V values. If there was some special syntax like Map[{Foo[A], Bar[A]} forSome {type A}] which would allow us to specify that for each entry in the Map, the As should match, then it would also be possible to use that syntax to specify the nonsense type NotMap[{Foo[A], Bar[A]} forSome {type A}]. Therefore there is no such syntax, and we need to use a type other than Map, such as DependentMap or HMap.
What about something like
def map[A]: Map[Foo[A], Bar[A]] = ...
val myMap = map[Qux]
...
val foo = new Foo[Qux]
val bar: Bar[Qux] = myMap(foo)
Or (inspired by Alexey Romanov's answer)
type MyMap[A] = Map[Foo[A],Bar[A]]
val map:MyMap[Qux] = ...
...
val foo = new Foo[Qux]
val bar: Bar[Qux] = map(foo)
I'm running into some kind of quirk in the Scala type system that has me a bit stumped. I am trying to make a class that extends Map[String,String] and I can't quite figure out how to implement the + method in such a way that the compiler accepts it.
Here's the code I have now:
class ParamMap(val pairs:List[(String,String)] = Nil) extends Map[String,String] {
lazy val keyLookup = Map() ++ pairs
override def get(key: String): Option[String] = keyLookup.get(key)
override def iterator: Iterator[(String, String)] = pairs.reverseIterator
/**
* Add a key/value pair to the map
*/
override def + [B1 >: String](kv: (String, B1)) = new ParamMap(kv :: pairs)
/**
* Remove all values for the given key from the map
*/
override def -(key: String): ParamMap = new ParamMap(pairs.filterNot(_._1 == key))
/**
* Remove a specific pair from the map
*/
def -(kv: (String, String)) : ParamMap = new ParamMap(pairs - kv)
}
Scala tells me this:
type mismatch; found: (String, B1) required: (String, String)
I believe this is because B1 is allowed to be a subtype of String but my constructor expects just a String (?). My original attempt was:
override def +(kv: (String, String)) = new ParamMap(kv :: pairs)
But this complained because the type signature didn't match the trait:
class ParamMap needs to be abstract, since method + in trait Map of type [B1 >: String](kv: (String, B1))scala.collection.immutable.Map[String,B1] is not defined
method + overrides nothing
I'm new to Scala and I think I'm getting over my head here in terms of how the type system works. Perhaps I'll try messing with casting but I have a feeling there might be a "better way" that, if I know it, will save me a lot of trouble in the future.
Any ideas?
Some background about Scala's type system.
The syntax B1 >: String means that B1 is a supertype of String. So B1 is less specific, and can't be cast to a String. Conversely, B1 <: String would be a subtype relationship.
The definition of the Map trait is Map [A, +B], where A represents the type of the key and B the type of the value. The +B notation says that Map is covariant in the key type, which means that T <: S implies Map[A, T] <: Map[A, S].
The full type of the Map.+ method is + [B1 >: B] (kv: (A, B1)): Map[A, B1]. The covariance of B kind of forces the use of B1 >: B. Here's an example of how it works: given a map m: Map[String, String] adding a key-value pair with a less specific type kv : (String, Any) will result in a less specific map, (m + kv): Map[String, Any].
The last point illustrates the problem with your ParamMap definition. According to the Map interface, one should be able to add a key of type Any to a map of type ParamMap <: Map[String, String] and get back a Map[String, Any]. But you're trying to define ParamMap.+ to always return ParamMap[String, String], which is incompatible with Map.+.
One way to fix the problem is to give ParamMap an explicit type parameter, something like (warning untested),
class ParamMap[B](val pairs:List[(String,String)] = Nil) extends Map[String, B] {
...
override def + [B1 >: B](kv: (String, B1)) = new ParamMap[B1](kv :: pairs)
}
but this may not be what you want. I don't think there's a way to fix the value type as String and implement the Map[String, String] interface.
Given all the above, why does the code in your answer compile? You've actually uncovered a limitation (unsoundness) of Scala's pattern matching, and it can lead to run-time crashes. Here's a simplified example:
def foo [B1 >: String](x: B1): Int = {
val (s1: Int, s2: Int) = (x, x)
s1
}
Although this compiles, it doesn't do anything useful. In fact, it will always crash with a MatchError:
scala> foo("hello")
scala.MatchError: (hello,hello) (of class scala.Tuple2)
at .foo(<console>:9)
at .<init>(<console>:10)
at .<clinit>(<console>)
...
In your answer, you've basically told the compiler to convert a B1 instance to a String, and if the conversion doesn't work, you'll get a runtime crash. It's equivalent to an unsafe cast,
(value: B1).asInstanceOf[String]
You're correct that your constructor expects a value of type List[String, String], but the issue isn't that B1 could be a subclass of String, it's that it could be a superclass -- this is what the B1 :> String notation indicates.
At first glance, you might wonder why the parent Map class would have the method typed this way. In fact, the return type of the + method you're attempting to override there is Map[String, B1]. In the context of a general map, though, this makes sense. Suppose you had the following code:
class Parent
class Child extends Parent
val childMap = Map[String, Child]("Key" -> new Child)
val result = childMap + ("ParentKey" -> new Parent)
The type of result would then have to be Map[String, Parent]. In light of this, the type restrictions on the + method in Map makes sense, but your fixed-type map isn't capable of fulfilling what the method is designed to be able to do. Its signature allows you to pass in a value of e.g. type (String, AnyRef), but using the method definition you gave in your followup answer, you'll get a MatchError when it tries to perform the assignment to key and value.
Does that make sense?
I ran the same problem with a colleague, when trying to build a Bag[T] which is a Map[T,Int]. We found two different solutions:
Implement Traversable rather than Map with appropriate Builder and CanBuildFrom, and add the useful map methods (get,+,-). If you need to pass the collection to a function taking maps as arguments, you can use implicit conversions. Here is our full Bag implementation: https://gist.github.com/1136259
Stay simple:
object collection {
type ParamMap = Map[String,String]
object ParamMap {
def apply( pairs: List[(String,String)] = Nil ) = Map( pairs:_* )
}
}
The compiler does seem to accept this one:
override def + [B1 >: String](kv: (String, B1)) = {
val (key:String, value:String) = kv
new ParamMap((key,value) :: pairs)
}
But I don't know why that is better than the original. I suppose this is an acceptable solution if nobody has a better one.