I am porting over code that was written in Python over to Scala.
This python code [0,{}] creates a list of an integer and a dictionary.
The dictionary in this case will have keys that are strings, but the values can either be an int or a string.
I want to do something similar in Scala. I believe I would have to do something like:
List[Any] = (<int>, scala.collection.mutable.Map[String, Any](...))
I plan to bencode this list so the underlying type of 'Any' matters. How do I change the types so that the list can be bencoded?
For the most part, using Any is not the right thing to do in Scala.
Since your problem is that the map values can be either Int or String, rather than trying to use their common type (Any), make your own new type hierarchy to represent the possibilities:
sealed trait BData
case class BInt(i: Int) extends BData
case class BString(s: String) extends BData
Now your map will have a type signature of Map[String, BData]
Using BData as the "underlying type" is better than using Any because there is no ambiguity to it. It has exactly two subclasses; compared with Any, where your values might be a List[(Foo, Bar)], for all the compiler knows.
I'll take dylan answer little further.
Scala have strong type system and you should use it.
When you are using Any which is like Object in java, you lose the type.
You should define the types and let the compiler work for you:
sealed trait BData[T] {
val value: T
}
implicit class BInt(val value: Int) extends BData[Int]
implicit class BString(val value: String) extends BData[String]
the 'implicit' declaration makes the compiler "Convert" the types for you, so you can use it like this:
val bDataMap = scala.collection.mutable.Map[String, BData[_]]()
val l = List((1, bDataMap))
l(0)._2 += ("myKey1" -> "Str")
l(0)._2 += ("myKey2" -> 2)
l(0)._2("myKey1").value
and so on....
Related
Given:
case class Foo(x: BigDecimal)
I'd like to, at compile-time, build a List[Foo] where each Foo must have a BigDecimal value of 5.
So, I'd expect the following code to compile:
type Foo5Only = ???
val foos5: List[Foo5Only] = List(Foo(5), Foo(5))
But, I'd expect the following to fail to compile:
val bad: List[Foo5Only] = List(Foo(42))
I'm speculating that a shapeless Singleton type might be useful, but I don't actually understand it.
Note - I'm not interested, for this question, in an answer that results in using Either or Option.
As well as using shapeless' Nat type you could also use singleton types. Unfortunately Scala's built-in List type has covariance which gets in the way of type safety, but using a simple hand-crafted list type seems to work:
import shapeless.syntax.singleton._
sealed trait Lst[T]
case class Nil[T]() extends Lst[T]
case class Cons[T](head : T, tail : Lst[T]) extends Lst[T]
def list[T](t : T) : Lst[T] = {
Cons(t, Nil())
}
// OK
val foos5 = Cons(5.narrow, list(5.narrow))
// Compile-time type mismatch error.
val foos6 = Cons(42.narrow, list(5.narrow))
You might be able to elide the narrows with some macro-magic, but that's beyond my ability.
I'm wondering the best way to achieve type-safety with my code when various values might all be Strings or Doubles, but are still incompatible. For example, I might have units in pounds and kilograms, but I should be forbidden to assign one to the other. Likewise, I might have a person ID as a String and a lookup table of animal IDs as a Map[String,Int], but I should be forbidden to look a person up in the animals table.
Conceptually I'm looking for something like this:
class PersonId extends String
class AnimalId extends String
var p : PersonId = "1234"
var tab : Map[AnimalId,Int] = Map("foo" -> 5, "bar" -> 6)
tab.get(p) // Want this to cause a compile error
But there are several problems making that not work. Suggestions for something that fits the spirit?
I'd use value classes for this. It behaves pretty much the same as a regular case class but the compiler places some restrictions on it, and generally it never has to actually waste time/memory creating the wrapper object - it can usually use the underlying value directly.
case class Person(value: String) extends AnyVal
case class Animal(value: String) extends AnyVal
You cannot extend String for obvious reasons. I suggest using case classes for that:
case class PersonId(id:String)
case class AnimalId(id:String)
Syntax gets a little bit more complicated, but not that much. And you can use case classes easily when pattern matching!
var p: PersonId = PersonId("1234")
var tab: Map[AnimalId,Int] = Map(AnimalId("foo") -> 5, AnimalId("bar") -> 6)
One simple solution is just use
case class PersonId(id:String)
case class AnimalId(id:String)
This solution is usually good enough.
If you want to play a bit with Scala's type system you can do something like that -
trait Person
trait Animal
case class IdOf[T](s: String) extends AnyVal
implicit def string2idOf[T](s: String): IdOf[T] = IdOf(s)
var p: IdOf[Person] = "1234"
var tab: Map[IdOf[Animal], Int] = Map(("foo": IdOf[Animal]) -> 5, ("bar": IdOf[Animal]) -> 6)
tab.get(p)
// Error:(25, 11) type mismatch;
// found : com.novak.Program.IdOf[com.novak.Program.Person]
// required: com.novak.Program.IdOf[com.novak.Program.Animal]
// tab.get(p)
^
Just another option is Scalaz's tagged type. Might be useful in some cases as it alows you to combine your type with some other type without creating new instance of this other type (value classes do simmilar for primitive types); however new Scalaz requires to explicitly unbox it (with Tag.unwrap), so not much useful as one can expect.
Example:
trait Person
val Person = Tag.of[Person]
val person = Prsn("Me")
Person.unwrap(person)
trait Animal
val Animal = Tag.of[Animal]
val animal = Anml("Me")
Animal.unwrap(person) //error
Animal.unwrap(animal)
Just quotes:
Suppose we want a way to express mass using kilogram, because kg is
the international standard of unit. Normally we would pass in Double
and call it a day, but we can’t distinguish that from other Double
values. Can we use case class for this?
case class KiloGram(value: Double)
Although it does adds type safety,
it’s not fun to use because we have to call x.value every time we need
to extract the value out of it. Tagged type to the rescue.
scala> sealed trait KiloGram defined trait KiloGram
scala> def KiloGram[A](a: A): A ## KiloGram = Tag[A, KiloGram](a)
KiloGram: [A](a: A)scalaz.##[A,KiloGram]
scala> val mass = KiloGram(20.0) mass: scalaz.##[Double,KiloGram] =
20.0
scala> sealed trait JoulePerKiloGram
defined trait JoulePerKiloGram
scala> def JoulePerKiloGram[A](a: A): A ## JoulePerKiloGram = Tag[A, JoulePerKiloGram](a)
JoulePerKiloGram: [A](a: A)scalaz.##[A,JoulePerKiloGram]
scala> def energyR(m: Double ## KiloGram): Double ## JoulePerKiloGram =
JoulePerKiloGram(299792458.0 * 299792458.0 * Tag.unsubst[Double, Id, KiloGram](m))
energyR: (m: scalaz.##[Double,KiloGram])scalaz.##[Double,JoulePerKiloGram]
scala> energyR(mass)
res4: scalaz.##[Double,JoulePerKiloGram] = 1.79751035747363533E18
scala> energyR(10.0)
<console>:18: error: type mismatch;
found : Double(10.0)
required: scalaz.##[Double,KiloGram]
(which expands to) AnyRef{type Tag = KiloGram; type Self = Double}
energyR(10.0)
^
I'm moving my first steps in Scala and I would like to make the following code works:
trait Gene[+T] {
val gene: Array[T]
}
The error that the compiler gives is: covariant type T occurs in invariant position in type => Array[T] of value gene
I know I could do something like:
trait Gene[+T] {
def gene[U >: T]: Array[U]
}
but this doesn't solve the problem because I need a value: pratically what I'm trying to say is "I don't care of the inside type, I know that genes will have a gene field that return its content". (the +T here is because I wanna do something like type Genome = Array[Gene[Any]] and then use it as a wrapper against the single gene classes so I can have a heterogeneous array type)
Is it possible to do it in Scala or I'm simply taking a wrong approach? Would it be better to use a different structure, like a Scala native covariant class?
Thanks in advance!
P.S.: I've also tried with class and abstract class instead than trait but always same results!
EDIT: with kind suggestion by Didier Dupont I came to this code:
package object ga {
class Gene[+T](val gene: Vector[T]){
def apply(idx: Int) = gene(idx)
override def toString() = gene.toString
}
implicit def toGene[T](a: Vector[T]) = new Gene(a)
type Genome = Array[Gene[Any]]
}
package test
import ga._
object Test {
def main(args: Array[String]) {
val g = Vector(1, 3, 4)
val g2 = Vector("a", "b")
val genome1: Genome = Array(g, g2)
println("Genome")
for(gene <- genome1) println(gene.gene)
}
}
So I now think I can put and retrieve data in different types and use them with all type checking goodies!
Array is invariant because you can write in it.
Suppose you do
val typed = new Gene[String]
val untyped : Gene[Any] = typed // covariance would allow that
untyped.gene(0) = new Date(...)
this would crash (the array in your instance is an Array[String] and will not accept a Date). Which is why the compiler prevents that.
From there, it depends very much on what you intend to do with Gene. You could use a covariant type instead of Array (you may consider Vector), but that will prevent user to mutate the content, if this was what you intended. You may also have an Array inside the class, provided it is decladed private [this] (which will make it quite hard to mutate the content too). If you want the client to be allowed to mutate the content of a Gene, it will probably not be possible to make Gene covariant.
The type of gene needs to be covariant in its type parameter. For that to be possible, you have to choose an immutable data structure, for example list. But you can use any data structure from the scala.collection.immutable package.
I want to map from class tokens to instances along the lines of the following code:
trait Instances {
def put[T](key: Class[T], value: T)
def get[T](key: Class[T]): T
}
Can this be done without having to resolve to casts in the get method?
Update:
How could this be done for the more general case with some Foo[T] instead of Class[T]?
You can try retrieving the object from your map as an Any, then using your Class[T] to “cast reflectively”:
trait Instances {
private val map = collection.mutable.Map[Class[_], Any]()
def put[T](key: Class[T], value: T) { map += (key -> value) }
def get[T](key: Class[T]): T = key.cast(map(key))
}
With help of a friend of mine, we defined the map with keys as Manifest instead of Class which gives a better api when calling.
I didnt get your updated question about "general case with some Foo[T] instead of Class[T]". But this should work for the cases you specified.
object Instances {
private val map = collection.mutable.Map[Manifest[_], Any]()
def put[T: Manifest](value: T) = map += manifest[T] -> value
def get[T: Manifest]: T = map(manifest[T]).asInstanceOf[T]
def main (args: Array[String] ) {
put(1)
put("2")
println(get[Int])
println(get[String])
}
}
If you want to do this without any casting (even within get) then you will need to write a heterogeneous map. For reasons that should be obvious, this is tricky. :-) The easiest way would probably be to use a HList-like structure and build a find function. However, that's not trivial since you need to define some way of checking type equality for two arbitrary types.
I attempted to get a little tricky with tuples and existential types. However, Scala doesn't provide a unification mechanism (pattern matching doesn't work). Also, subtyping ties the whole thing in knots and basically eliminates any sort of safety it might have provided:
val xs: List[(Class[A], A) forSome { type A }] = List(
classOf[String] -> "foo", classOf[Int] -> 42)
val search = classOf[String]
val finalResult = xs collect { case (`search`, result) => result } headOption
In this example, finalResult will be of type Any. This is actually rightly so, since subtyping means that we don't really know anything about A. It's not why the compiler is choosing that type, but it is a correct choice. Take for example:
val xs: List[(Class[A], A) forSome { type A }] = List(classOf[Boolean] -> 'bippy)
This is totally legal! Subtyping means that A in this case will be chosen as Any. It's hardly what we want, but it is what you will get. Thus, in order to express this constraint without tracking all of the types individual (using a HMap), Scala would need to be able to express the constraint that a type is a specific type and nothing else. Unfortunately, Scala does not have this ability, and so we're basically stuck on the generic constraint front.
Update Actually, it's not legal. Just tried it and the compiler kicked it out. I think that only worked because Class is invariant in its type parameter. So, if Foo is a definite type that is invariant, you should be safe from this case. It still doesn't solve the unification problem, but at least it's sound. Unfortunately, type constructors are assumed to be in a magical super-position between co-, contra- and invariance, so if it's truly an arbitrary type Foo of kind * => *, then you're still sunk on the existential front.
In summary: it should be possible, but only if you fully encode Instances as a HMap. Personally, I would just cast inside get. Much simpler!
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/