This page is no longer maintained — Please continue to the home page at www.scala-lang.org

"Strongly typed" Map over subtypes

3 replies
Patrick Roemer
Joined: 2009-02-18,
User offline. Last seen 42 years 45 weeks ago.

Hi,

I'm wondering whether there is any clean way to implement a map that
stores "more specifically typed" key/value pairs than the map's generic
type. To add to the fun, the key should be a class.

trait TypeMap[T] {
def put[S <: T](key: Class[S], value: S): Unit
def get[S <: T](key: Class[S]): Option[S]
}

(The idea is to have a map from interfaces to implementations, for
example for a naive plugin environment. The question originated from a
Java-based discussion where you would use wildcards and casts and live
with the compiler warnings.)

The best I could achieve so far was a "roll-your-own" map based on
something like

case class SimpleTypeMapEntry[S](val key: Class[S], val value: S)
private val entries: Set[SimpleTypeMapEntry[S] forSome { type S <: T }]

and

v match {
case Some(s: S) => v
case x => None
}

But this definitely feels like cheating. Is there any better way without
the match, which just seems like a cast in disguise? (And preferably
based on a standard collection - but how to get the class type right in
that case?)

Best regards,
Patrick

Derek Williams
Joined: 2009-06-13,
User offline. Last seen 42 years 45 weeks ago.
Re: "Strongly typed" Map over subtypes
I just spent a good part of the last couple days working on a similar problem, my requirements might be slightly different though:
1. Must be serializable to/from Json
2. Must be immutable
3. Must be typesafe (I'm not sure on how safe I am yet, but my tests pass so far)
4. Must not use excessive memory (haven't tested this one out yet)

Due to needing an easy way to deserialize from json, I needed to have all the possible keys organized in one place as I look them up with reflection, so this might not be the direction you want to go. I'm also teaching myself much more scala concepts with this code too, and my grasp of them might not be as strong as I think they are.

You can see my (very much inprogress) code currently in the lift project I'm playing with:
http://github.com/nebbie/williams_family
And see the relevant files:
/src/main/scala/ca/williams_family/model/Document.scala
/src/main/scala/ca/williams_family/model/Photo.scala
/src/test/scala/ca/williams_family/model/PhotoSpec.scala

Sam Stainsby
Joined: 2009-01-14,
User offline. Last seen 42 years 45 weeks ago.
Re: "Strongly typed" Map over subtypes

On Mon, 14 Sep 2009 13:18:42 +0200, Patrick Roemer wrote:

> (The idea is to have a map from interfaces to implementations, for
> example for a naive plugin environment. The question originated from a
> Java-based discussion where you would use wildcards and casts and live
> with the compiler warnings.)

We have a package (currently pre-alpha, mostly undocumented) where we do
this sort of "naive plugin" thing (we call them "resources"):

http://uniscala.net/uniscala-ctx/scaladocs/index.html

I use an ordinary Scala map, but it is hidden away from the api user.
Rather than accessing the map directly, the mapping from each interface T
to implementation is passed in as a "ContextMapping[T]" which type-safely
ensures that the implementation is compatible with the interface.

To digress a little in case this is also interesting ...

I also use a bit of Manifest trickery to make it look neater to the api
user. Add some implicits and you can get code to map interface to
implementations as easily as this:

ctx = new SimpleImmutableUniversalContext(
ContextMapping[ObjectContainer](new RequestCycleDb4oContext),
Provider[ActionRegister](actionRegister),
Provider[MutableActionRegister](actionRegister),
Provider[AuthenticationRealmRegister](authRegister),
Provider[MutableAuthenticationRealmRegister](authRegister),
Provider[MultiViewFactory](viewFactory),
Provider[MutableMultiViewFactory](viewFactory)
)
}

- its a bit more complicated than your scenario - I won't try to go into
the difference between Contexts, Lenders and Providers and their Generic/
Universal counterparts here.

Once you have the context you can do this (again using Manifests to
neaten things):

context.useOrFail { register:ActionRegister => // do stuff ... }

There is also 'useOrElse'. The whole thing is still evolving, but proving
very useful in the framework I'm developing.

Adriaan Moors
Joined: 2009-04-03,
User offline. Last seen 42 years 45 weeks ago.
Re: "Strongly typed" Map over subtypes
Hi,
I think Section 6 of http://lamp.epfl.ch/%7Eemir/written/MatchingObjectsWithPatterns-TR.pdf may be relevant here.
cheersadriaan

On Mon, Sep 14, 2009 at 1:18 PM, Patrick Roemer <sangamon [at] netcologne [dot] de> wrote:
Hi,

I'm wondering whether there is any clean way to implement a map that
stores "more specifically typed" key/value pairs than the map's generic
type. To add to the fun, the key should be a class.

trait TypeMap[T] {
 def put[S <: T](key: Class[S], value: S): Unit
 def get[S <: T](key: Class[S]): Option[S]
}

(The idea is to have a map from interfaces to implementations, for
example for a naive plugin environment. The question originated from a
Java-based discussion where you would use wildcards and casts and live
with the compiler warnings.)

The best I could achieve so far was a "roll-your-own" map based on
something like

case class SimpleTypeMapEntry[S](val key: Class[S], val value: S)
private val entries: Set[SimpleTypeMapEntry[S] forSome { type S <: T }]

and

v match {
 case Some(s: S) => v
 case x => None
}

But this definitely feels like cheating. Is there any better way without
the match, which just seems like a cast in disguise? (And preferably
based on a standard collection - but how to get the class type right in
that case?)

Best regards,
Patrick


Disclaimer: http://www.kuleuven.be/cwis/email_disclaimer.htm

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland