I have a Scala code:
import collection.mutable._
def myMethod(mycollection: Map[A, B]) = {
...
}
How do I call this method?
Tried this:
myMethod(["test1", "test2"])
Got error:
Identifier expected but 'def' found
Thanks.
A Map is a data structure that maps a key (of some type K) to a value (of some type V). In Scala, such a pair can be denoted by the syntax key -> value. If your intent is to have a single String key "test1" that maps to a String value of "test2", then you can do that as follows:
Map("test1" -> "test2")
Your declaration of myMethod is invalid: you need to either define actual types for A and B or make them generic parameters for your method (so that the method is generic):
// With specific types (assuming both keys and values have String types):
def myMethod(mycollection: Map[String, String]) = //...
// In generic form (allows any key type A, or value type B):
def myMethod[A, B](mycollection: Map[A, B]) = //...
Either way, you can then use the result as the argument in a call to your method as follows:
myMethod(Map("test1" -> "test2"))
Some points to note:
Square brackets are used when defining generic type parameters, or specifying the types used as type parameters.
Type parameters can be inferred from the values supplied. For example Map("test1" -> "test2") uses String as the type for both the key and the value, and is equivalent to Map[String, String]("test1" -> "test2").
If you need more than one key/value pair, list them with a comma separator, for example: Map("key1" -> "value1", "key2" -> "value2", "key3" -> "value3")
I strongly recommend that you read a good book on Scala, such as the excellent Programming in Scala, 3rd Edition by Odersky, Spoon & Venners, in order to become familiar with its syntax and standard library.
As a final point, I would strongly recommend that you use the immutable version of Map whenever possible. If you're not familiar with functional programming principles, this will seem unusual at first, but the benefits are huge.
Related
I have the following code which is working:
case class Step() {
def bindings(): Map[String, Any] = ???
}
class Builder {
private val globalBindings = scala.collection.mutable.HashMap.empty[String, Any]
private val steps = scala.collection.mutable.ArrayBuffer.empty[Step]
private def context: Map[String, Any] =
globalBindings.foldLeft(Map[String, Any]())((l, r) => l + r) ++ Map[String, Any]("steps" -> steps.foldLeft(Vector[Map[String, Any]]())((l, r) => l.+:(r.bindings)))
}
But I think it could be simplified so as to not need the first foldLeft in the 'context' method.
The desired result is to produce a map where the entry values are either a String, an object upon which toString will be invoked later, or a function which returns a String.
Is this the best I can do with Scala's type system or can I make the code clearer?
TIA
First of all, the toMap method on mutable.HashMap returns an immutable.Map. You can also use map instead of the inner foldLeft together with toVector if you really need a vector, which might be unnecessary. Finally, you can just use + to add the desired key-value pair of "steps" to the map.
So your whole method body could be:
globalBindings.toMap + ("steps" -> steps.map(_.bindings).toVector)
I'd also note that you should be apprehensive of using types like Map[String, Any] in Scala. So much of the power of Scala comes from its type system and it can be used to great effect in many such situations, and so these types are often considered unidiomatic. Of course, there are situations where this approach makes the most sense, and without more context it would be hard to determine if that were true here.
I am looking for implementation of heterogeneous map. By heterogeneous map I mean a structure HMap[KeyType, Any] with defined methods:
get[ValueType](key : KeyType] : Option[ValueType]
+(key : KeyType, value : Any) : HMap[KeyType, Any]
There are answers on Stack Overflow telling how to implement it using Manifests/ClassTags and I have a basic version:
class TypedMap[K](
val inner:Map[(K, TypeTag[_]), Any]){
def +[V](key: K, value: V)(implicit tag:TypeTag[V]) = new TypedMap[K](inner + ((key, tag) -> value))
def apply[V](key:K)(implicit tag:TypeTag[V]) = inner.apply((key, tag)).asInstanceOf[V]
def get[V](key:K)(implicit tag:TypeTag[V]) = inner.get((key, tag)).asInstanceOf[Option[V]]
}
val a = new TypeMap(Map(("key1" -> 1),("key2" -> "two")))
a.get[Int]("key1")
a.get[String]("key2")
I wonder if there is an existing more complete implementation with additional functionality as in standard collections Map.
The usecase is reading unknown number of columns from csv/mongo/sql (some types are unknown in compile time), transforming some of the columns (their types are known in compile time), adding new ones and transferring the results map to R data.frame through rJava. In my particular case I need Map[String, Double/Int/String/Boolean/Date] if a less generic solution is somehow easier.
The short ClassTag and Manifest solutions are described in:
How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?
Scala: What is a TypeTag and how do I use it?
I have found several small github solutions:
https://github.com/EnMAS/EnMAS-Framework/blob/master/enmas-core/src/main/scala/org/enmas/pomdp/State.scala
https://github.com/kennknowles/scala-heterogeneous-map
What I am not looking for:
Compiler magic to infer in compile time the return type that is unknown in compile time - impossible
Shapeless HMap – I need to distinguish between (String -> Int) and (String -> String)
Inherit from scala.collections.Map – impossible because for Map[A, B] get is get[B] which is in my case get[Any]
I have a special Map that will eventually do some consistency checking of values, which are restricted to have special meaning. For now I just want to create a Schema that acts exactly like a Map[String, Any], in particular I'd like to instantiate is with a list of mappings, and not force the types for the Map to be specified, so they are always [String, Any]. So instead of
val myMap:Map[String,Any] = Map("one" -> 1, "two" -> "2", ...)
I'd like to be able to have:
val mySchema:Schema = Schema("one" -> 1, "two" -> "2", ...)
Map is a trait so I think I need to extend a class like HashMap
class Schema extends HashMap[String, Any]
when I instantiate it with a list of initial mappings I get
val mySchema = new Schema("one" -> 1, "two" -> "2", ...)
Error:(110, 19) too many arguments for constructor Schema: ()drivers.Schema
val mySchema = new Schema("one" -> 1, "two" -> "2")
^
There is some magic inside HashMap that is far beyond me to read (it extends 1 class with 5 traits). But it looks like the constructor's "contents" (a list of mappings?) are passed to something's initWithContents(contents) pseudo constructor. Do I need something like that there?
class Schema(elems: Tuple2[String, Any]*) extends HashMap[String, Any] {
this ++= elems
}
val mySchema = new Schema("one" -> 1, "two" -> "2")
Explanation:
-> is syntactic sugar for a tuple, so the constructor type is a variable number of tuples
The "normal" way of constructing a Map/HashMap calls the apply method in the companion object which is implemented in GenMapFactory.scala.
Unfortunately, this does not work for an immutable HashMap. As far as I can tell, the only way to "extend" an immutable HashMap is by creating a class that holds an internal reference to one, as described e.g. in this answer to a similar question on SO.
You'll notice that the syntax you're using to create the Schema instance is slightly different than your target syntax as well as the standard Map syntax:
Schema("one" -> 1, "two" -> "2", ...)
new Schema("one" -> 1, "two" -> "2", ...)
Map("one" -> 1, "two" -> "2", ...)
In particular, there is a new in the second case. When you create a Map without new, you are invoking a function called apply on a companion module of the same name. In this case, the function which accepts a variable length sequence of arguments is defined the Map object's inherited GenMapFactory type and it has this signature:
def apply[A, B](elems: (A, B)*): CC[A, B] = (newBuilder[A, B] ++= elems).result
The magic derives the from Scala compiler resolving this method, because methods in the companion module are part of its implicit scope. You will need to do something similar in by adding a Schema object:
object Schema {
def apply(entries: (String, Any)*) = new Schema() ++ entries
}
If you define the object, this will work:
Schema("one" -> 1, "two" -> "2") // scala.collection.immutable.Map[String,Any](one -> 1, two -> 2)
One downside of this approach is that you lose type specificity after construction, but if you're just performing consistency checking on creation this may be enough. If you want the Schema type to be returned on invocation of the apply function or returned by other methods calls implemented in super types and enclosing scope, you will probably need to integrate with the Scala 2.8 collections API as documented here.
I encountered some unauthorized strangeness working with Scala's SortedMap[A,B]. If I declare the reference to SortedMap[A,B] "a" to be of type Map[A,B], then map operations on "a" will produce a non-sorted map implementation.
Example:
import scala.collection.immutable._
object Test extends App {
val a: Map[String, String] = SortedMap[String, String]("a" -> "s", "b" -> "t", "c" -> "u", "d" -> "v", "e" -> "w", "f" -> "x")
println(a.getClass+": "+a)
val b = a map {x => x} // identity
println(b.getClass+": "+b)
}
The output of the above is:
class scala.collection.immutable.TreeMap: Map(a -> s, b -> t, c -> u, d -> v, e -> w, f -> x)
class scala.collection.immutable.HashMap$HashTrieMap: Map(e -> w, f -> x, a -> s, b -> t, c -> u, d -> v)
The order of key/value pairs before and after the identity transformation is not the same.
The strange thing is that removing the type declaration from "a" makes this issue go away. That's fine in a toy example, but makes SortedMap[A,B] unusable for passing to methods that expect Map[A,B] parameters.
In general, I would expect higher order functions such as "map" and "filter" to not change the fundamental properties of the collections they are applied to.
Does anyone know why "map" is behaving like this?
The map method, like most of the collection methods, isn't defined specifically for SortedMap. It is defined on a higher-level class (TraversableLike) and uses a "builder" to turn the mapped result into the correct return type.
So how does it decide what the "correct" return type is? Well, it tries to give you back the return type that it started out as. When you tell Scala that you have a Map[String,String] and ask it to map, then the builder has to figure out how to "build" the type for returning. Since you told Scala that the input was a Map[String,String], the builder decides to build a Map[String,String] for you. The builder doesn't know that you wanted a SortedMap, so it doesn't give you one.
The reason it works when you leave off the the Map[String,String] type annotation is that Scala infers that the type of a is SortedMap[String,String]. Thus, when you call map, you are calling it on a SortedMap, and the builder knows to construct a SortedMap for returning.
As far as your assertion that methods shouldn't change "fundamental properties", I think you're looking at it from the wrong angle. The methods will always give you back an object that conforms to the type that you specify. It's the type that defines the behavior of the builder, not the underlying implementation. When you think about like that, it's the type that forms the contract for how methods should behave.
Why might we want this?
Why is this the preferred behavior? Let's look at a concrete example. Say we have a SortedMap[Int,String]
val sortedMap = SortedMap[Int, String](1 -> "s", 2 -> "t", 3 -> "u", 4 -> "v")
If I were to map over it with a function that modifies the keys, I run the risk of losing elements when their keys clash:
scala> sortedMap.map { case (k, v) => (k / 2, v) }
res3: SortedMap[Int,String] = Map(0 -> s, 1 -> u, 2 -> v)
But hey, that's fine. It's a Map after all, and I know it's a Map, so I should expect that behavior.
Now let's say we have a function that accepts an Iterable of pairs:
def f(iterable: Iterable[(Int, String)]) =
iterable.map { case (k, v) => (k / 2, v) }
Since this function has nothing to do with Maps, it would be very surprising if the result of this function ever had fewer elements than the input. After all, map on a Iterable should produce the mapped version of each element. But a Map is an Iterable of pairs, so we can pass it into this function. So what happens in Scala when we do?
scala> f(sortedMap)
res4: Iterable[(Int, String)] = List((0,s), (1,t), (1,u), (2,v))
Look at that! No elements lost! In other words, Scala won't surprise us by violating our expectations about how map on an Iterable should work. If the builder instead tried to produce a SortedMap based on the fact that the input was a SortedMap, then our function f would have surprising results, and this would be bad.
So the moral of the story is: Use the types to tell the collections framework how to deal with your data. If you want your code to be able to expect that a map is sorted, then you should type it as SortedMap.
The signature of map is:
def
map[B, That](f: ((A, B)) ⇒ B)(implicit bf: CanBuildFrom[Map[A, B], B, That]): That
The implicit parameter bf is used to build the resulting collection. So in your example, since the type of a is Map[String, String], the type of bf is:
val cbf = implicitly[CanBuildFrom[Map[String, String], (String, String), Map[String, String]]]
Which just builds a Map[String, String] which doesn't have any of the properties of the SortedMap. See:
cbf() ++= List("b" -> "c", "e" -> "g", "a" -> "b") result
For more information, see this excellent article: http://docs.scala-lang.org/overviews/core/architecture-of-scala-collections.html
As dyross points out, it's the Builder, which is chosen (via the CanBuildFrom) on the basis of the target type, which determines the class of the collection that you get out of a map operation. Now this might not be the behaviour that you wanted, but it does for example allow you select the target type:
val b: SortedMap[String, String] = a.map(x => x)(collection.breakOut)
(breakOut gives a generic CanBuildFrom whose type is determined by context, i.e. our type annotation.)
So you could add some type parameters that allow you accept any sort of Map or Traversable (see this question), which would allow you do do a map operation in your method while retaining the correct type information, but as you can see it's not straightforward.
I think a much simpler approach is instead to define functions that you apply to your collections using the collections' map, flatMap etc methods, rather than by sending the collection itself to a method.
i.e. instead of
def f[Complex type parameters](xs: ...)(complex implicits) = ...
val result = f(xs)
do
val f: X => Y = ...
val results = xs map f
In short: you explicitly declared a to be of type Map, and the Scala collections framework tries very hard for higher order functions such as map and filter to not change the fundamental properties of the collections they are applied to, therefore it will also return a Map since that is what you explicitly told it you wanted.
By dictionary I mean a lightweight map from names to values that can be used as the return value of a method.
Options that I'm aware of include making case classes, creating anon objects, and making maps from Strings -> Any.
Case classes require mental overhead to create (names), but are strongly typed.
Anon objects don't seem that well documented and it's unclear to me how to use them as arguments since there is no named type.
Maps from String -> Any require casting for retrieval.
Is there anything better?
Ideally these could be built from json and transformed back into it when appropriate.
I don't need static typing (though it would be nice, I can see how it would be impossible) - but I do want to avoid explicit casting.
Here's the fundamental problem with what you want:
def get(key: String): Option[T] = ...
val r = map.get("key")
The type of r will be defined from the return type of get -- so, what should that type be? From where could it be defined? If you make it a type parameter, then it's relatively easy:
import scala.collection.mutable.{Map => MMap}
val map: MMap[String, (Manifest[_], Any) = MMap.empty
def get[T : Manifest](key: String): Option[T] = map.get(key).filter(_._1 <:< manifest[T]).map(_._2.asInstanceOf[T])
def put[T : Manifest](key: String, obj: T) = map(key) = manifest[T] -> obj
Example:
scala> put("abc", 2)
scala> put("def", true)
scala> get[Boolean]("abc")
res2: Option[Boolean] = None
scala> get[Int]("abc")
res3: Option[Int] = Some(2)
The problem, of course, is that you have to tell the compiler what type you expect to be stored on the map under that key. Unfortunately, there is simply no way around that: the compiler cannot know what type will be stored under that key at compile time.
Any solution you take you'll end up with this same problem: somehow or other, you'll have to tell the compiler what type should be returned.
Now, this shouldn't be a burden in a Scala program. Take that r above... you'll then use that r for something, right? That something you are using it for will have methods appropriate to some type, and since you know what the methods are, then you must also know what the type of r must be.
If this isn't the case, then there's something fundamentally wrong with the code -- or, perhaps, you haven't progressed from wanting the map to knowing what you'll do with it.
So you want to parse json and turn it into objects that resemble the javascript objets described in the json input? If you want static typing, case classes are pretty much your only option and there are already libraries handling this, for example lift-json.
Another option is to use Scala 2.9's experimental support for dynamic typing. That will give you elegant syntax at the expense of type safety.
You can use approach I've seen in the casbah library, when you explicitly pass a type parameter into the get method and cast the actual value inside the get method. Here is a quick example:
case class MultiTypeDictionary(m: Map[String, Any]) {
def getAs[T <: Any](k: String)(implicit mf: Manifest[T]): T =
cast(m.get(k).getOrElse {throw new IllegalArgumentException})(mf)
private def cast[T <: Any : Manifest](a: Any): T =
a.asInstanceOf[T]
}
implicit def map2multiTypeDictionary(m: Map[String, Any]) =
MultiTypeDictionary(m)
val dict: MultiTypeDictionary = Map("1" -> 1, "2" -> 2.0, "3" -> "3")
val a: Int = dict.getAs("1")
val b: Int = dict.getAs("2") //ClassCastException
val b: Int = dict.getAs("4") //IllegalArgumetExcepton
You should note that there is no real compile-time checks, so you have to deal with all exceptions drawbacks.
UPD Working MultiTypeDictionary class
If you have only a limited number of types which can occur as values, you can use some kind of union type (a.k.a. disjoint type), having e.g. a Map[Foo, Bar | Baz | Buz | Blargh]. If you have only two possibilities, you can use Either[A,B], giving you a Map[Foo, Either[Bar, Baz]]. For three types you might cheat and use Map[Foo, Either[Bar, Either[Baz,Buz]]], but this syntax obviously doesn't scale well. If you have more types you can use things like...
http://cleverlytitled.blogspot.com/2009/03/disjoint-bounded-views-redux.html
http://svn.assembla.com/svn/metascala/src/metascala/OneOfs.scala
http://www.chuusai.com/2011/06/09/scala-union-types-curry-howard/