I am implementing a datastructure and want the user to be able to use any type as key as long as he provides a suitable key type wrapping it. I have a trait for this key type. The idea is to have implicit conversions from base to key type and the other way round to (virtually) just use the base type. The trait looks like this:
trait Key[T] extends Ordered[Key[T]] {
def toBase : T
// Further stuff needed for datastructure...
}
object Key {
implicit def key2base[T](k : Key[T]) : T = k.toBase
}
Call site code could look like this:
def foo[K <% Key[K]]( bar : Seq[K] ) = bar.sorted(0)
Plan is that values of type K
should be implicitly converted to Key[K]
which is ordered or the ordering on Key[K]
should be implcitly used, respectively, so everything should work out. Of course, there is no way to implement implicit base2key
in the trait itself. Or is there, maybe using implicitly passed class manifests? I could not find any references considering this.
Is it possible to somehow assert statically that any type extending Key[T]
will come with an implicit conversion T => Key[T]
? The companion object can not have abstract methods, sadly.
Assume this works out, is the entire enterprise feasible or will the stated use case need multiple chained implicit conversions, anyway? (Chaining does not happen, as I have read.)
Addendum: With above definition, I can sort a sequence of Node(key : K, ...)
(under K <% Key[K]
) by using sortWith(_.key <= _.key)
, but not using sortBy(_.key)
. So, obviously, the conversion from K
to Key[K]
happens implicitly, even though it is never declared anywhere by me, but there is no Ordering
on Key[K]
available implicitly. What is going on here?
Here is possible solution to your problem (hope I understood your requirements correctly):
In this case
Key[T]
is wrapper for typeT
andKeyable[T]
is type calss that allows to convert typeT
toKey[T]
. I also showed howbase2key
can look like.you ask "Is it possible to somehow assert statically that any type extending
Key[T]
will come with an implicit conversionT => Key[T]
? The companion object can not have abstract methods, sadly."but your example is a static assertion : when you require a view from
T
toKey[T]
, you assert at compile time that you may only callfoo
for types which can be lifted to keys. Or am i misunderstanding something?regarding the addendum: you say you are surprised that "the conversion from
K
toKey[K]
happens implicitly, even though it is never declared anywhere by me". thing is, you did declare it:T <% Key[T]
(I am usingT
here instead ofK
, you seem to be mixing up the notion of base *T*ype and *K*ey here?). This is identical tothus, when you do
sortWith(_ <= _)
you coerceT
intoKey[T]
(for which<=
is defined as per traitOrdered[Key[T]]
).taking your Node example, why not do
hope that helps...
In this answer, I will keep the currently best version for reference. Using this answer to more focused question; will be obsolete with 2.9 according to this one.
The
Key
trait remains unchanged; I add a specific function for illustration:The following works as expected (if
import Key._
is done):Let us assume we have a simple
class Node[K](val key : K)
. Again, things work as expected:For another example, assume this code using only the
Key[T]
interface:Note that this compiles since
map
yields aSeq[Key[K]]
directly; no conversion needed for sorting. Now, if we have a proper implementation ofKey
, saythe following should work:
But actually, the conversion from
StringKey
toString
is not found:This is strange; there is a conversion from
Key[String]
toString
, if declared with a generic type parameter.