collections - Binding Existential types in Scala -


this basic cmap map classes (class[t] t) type of value.

scala> type cmap = map[class[t] forsome{type t}, any] defined type alias cmap  scala> val cmap: cmap = map(classof[int]->5, classof[string]->"abc", classof[double]->"ddd") cmap: cmap = map(int -> 5, class java.lang.string -> abc, double -> ddd) 

now want "bound" cmap (call cmapbind). cmap, maps classes (any classes) values (any values). unlike cmap, cmapbind has type binding between key , value, meaning hope following behavior:

val cmapbind: cmapbind = map(classof[int]->5, classof[string]-> "aa") // should compile val cmapbind: cmapbind = map(classof[int]->5, classof[string]-> 0)    // should fail compile 

how implement cmapbind?

i know following 2 won't work syntactically/logically.

scala> type cmapbind = map[class[t] forsome{type t}, t] <console>:8: error: not found: type t        type cmapbind = map[class[t] forsome{type t}, t]   scala> type cmapbind = map[class[t], t] forsome{type t} scala> val cmapbind: cmapbind = map(classof[int]->5, classof[string]->"str") <console>:8: error: type mismatch;  found   : scala.collection.immutable.map[class[_ >: string int],any]  required: cmapbind     (which expands to)  map[class[t],t] forsome { type t }        val cmapbind: cmapbind = map(classof[int]->5, classof[string]->"str") 

note here using type constructor class[t] example illustrate question. in code have own types, e.g. trait animal[s, t], class dog extends animal[int, string].

edit 1: should have mentioned using immutable map example, need mutable heterogeneous map).

let's try implement mutable hmap. explanations scala type system here @milessabin: http://www.chuusai.com/2011/07/16/fundeps-in-scala/

the idea statically check constructor (here see, it's arity depends on hands, possible generate or smth else), , insert method. way, same way immutable hmap implemented in shapeless.

import scala.collection.mutable.map  class hmapbuilder[r[_, _]] { // constructor arity 2   def apply[k1, v1](e1: (k1, v1))(implicit ev1: r[k1, v1]) =      new hmap[r](map(e1))   def apply[k1, v1, k2, v2](e1: (k1, v1), e2: (k2, v2))                            (implicit ev1: r[k1, v1], ev2: r[k2, v2]) =     new hmap[r](map(e1, e2)) } 

so constructor of our map. evidences statically check types of inserting data. next, lets wrap default scala collection:

class hmap[r[_, _]](underlying : map[any, any] = map.empty) {   def get[k, v](k : k)(implicit ev : r[k, v]) : option[v] =      underlying.get(k).asinstanceof[option[v]]    def +=[k, v](kv : (k, v))(implicit ev : r[k, v]) : hmap[r] = {     underlying += kv       }   def -=[k](k : k) : hmap[r] = {     underlying -= k       }    override def tostring = underlying.tostring } 

finally wrapping hmapbuilder, make pleasant constructor:

object hmap {   def apply[r[_, _]] = new hmapbuilder[r]    def empty[r[_, _]] = new hmap[r]   def empty[r[_, _]](underlying : map[any, any]) =      new hmap[r](underlying) } 

in result, usage similar shapeless hmap:

class mapping[k, v]  implicit def mappingfromclass[a] = new mapping[class[a], a]  val hm = hmap[mapping](classof[int] -> 5) // ok hm += (classof[string] -> "string") // ok hm += (classof[boolean] -> false) // ok hm += (classof[double] -> "sss") // compile fail     

works expected. implemented insert , remove functions, other functions possible define same way.


Comments