generics, classOf[] and x.getClass

1,545 views
Skip to first unread message

Konstantine Kougios

unread,
Mar 1, 2011, 6:51:17 PM3/1/11
to scala...@googlegroups.com
Hi, I am struggling with this for a while. I have a Map[String,Class] and I want to use it within a class:

object Schema
{
    private var serializers:Map[Class[_],Serializer[_]]=Map(
            (classOf[Int],IntSerializer),
            (classOf[Double],DoubleSerializer),
            (classOf[Boolean],BooleanSerializer),
            (classOf[DateTime],DateSerializer)
        )

    def getSerializer(forClass:Class[_]):Serializer[_] = serializers(forClass)
...
}

attempt 1:

    def f[T](t:T) =getSerializer(classOf[t])

err: not found: type t
I assume this is cause classOf works during compilation and type of t is not known during compilation.

attempt 2:

    def f[T](t:T) =getSerializer(t.getClass)

err: type mismatch;  found   : T  required: ?{val getClass: ?} Note that implicit conversions are not applicable because they are ambiguous:  both method any2stringadd in object Predef of type (x: Any)scala.runtime.StringAdd  and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]  are possible conversion functions from T to ?{val getClass: ?}

Now, I would expect #2 to work but scala is mumbling something about PreDef and Strings which is very weird at this point as I am not working with Strings (I know though there is a perfectly logical explanation)

Any ideas on how to getSerializer from a generic variable t?

Thanks

Volodymyr Kyrychenko

unread,
Mar 1, 2011, 6:53:11 PM3/1/11
to scala...@googlegroups.com
Konstantine Kougios wrote:
> Hi, I am struggling with this for a while. I have a Map[String,Class]
> and I want to use it within a class:
>
> object Schema
> {
> private var serializers:Map[Class[_],Serializer[_]]=Map(
> (classOf[Int],IntSerializer),
> (classOf[Double],DoubleSerializer),
> (classOf[Boolean],BooleanSerializer),
> (classOf[DateTime],DateSerializer)
> )
>
> def getSerializer(forClass:Class[_]):Serializer[_] =
> serializers(forClass)
> ...
> }
>
> attempt 1:
>
> def f[T](t:T) =getSerializer(classOf[t])

def f[T:Manifest](t:T) =getSerializer(manifest[T].erasure)

--
Best Regards,
Volodymyr Kyrychenko

signature.asc

Roland Kuhn

unread,
Mar 2, 2011, 7:13:09 PM3/2/11
to Konstantine Kougios, scala...@googlegroups.com
try [T <: AnyRef], otherwise T like Any which does not have .getClass. 

Konstantine Kougios

unread,
Mar 3, 2011, 1:38:49 PM3/3/11
to Roland Kuhn, scala...@googlegroups.com
Hi, that's what I am doing right now, but it is not 100% clean solution when it comes to anything extending AnyVal. i.e. all Int types are converted to java.lang.Integer. This means that my map doesn't contain a value for it:


var serializers:Map[Class[_],Serializer[_]]=Map(
            (classOf[Int],IntSerializer),
            (classOf[Double],DoubleSerializer),
            (classOf[Boolean],BooleanSerializer),
            (classOf[DateTime],DateSerializer)
        )


classOf[Int] != java.lang.Integer

In fact my map contains a mapping for java.lang.Integer but with IntegerSerializer instead of IntSerializer. Hence when I do serializers(5), it is serialized with IntegerSerializer instead of IntSerializer. There is a subtle difference between those two Serializers and I want to use the correct one.

So I am kind of stuck and the only solution I can see is to do pattern matching for AnyVal types and use the map only for the default matcher, i.e.

v match {
    case i:Int => IntSerializer
    case d:Double => DoubleSerializer
...
    case ar:AnyRef  => serializers(ar)
}

Regards,

Kostas

Lex

unread,
Mar 3, 2011, 2:38:01 PM3/3/11
to Konstantine Kougios, Roland Kuhn, scala...@googlegroups.com
When you have an undefined AnyVal type, it will be wrapped as java.lang.Integer/Float/Double/etc. So AnyVal becomes AnyRef behind the scenes. So your matcher will works the same as calling "serializers(ar)". Other than using ClassManifests/Manifests, there is absolutely no way to distinguish between a wrapped AnyVal and java.lang.Number types.

If you are relying on "the subtle difference" between Int serializer and Integer serializer, you are doing something wrong. My guess you want the null value. In this case you should be using Option[Int] instead.

Konstantine Kougios

unread,
Mar 3, 2011, 6:22:37 PM3/3/11
to Lex, Roland Kuhn, scala...@googlegroups.com
Yes, null is one issue and I am using Option[] too. My idea was to treat AnyVals properly but if they are not different from their corresponding java wrapper classes, then I suppose I can use the java ones.

Now I am facing a different issue. Do you know how can I convert a Class[_] to i.e. Class[Int] or Class[Boolean]? The problem is a bit complicated but let me try explaining:

The syntax below

    val schema1=Schema(
            ("first",classOf[String]),
            ("last",classOf[String]),
            ("age",classOf[Int]),
            ("born",classOf[DateTime]),
            ("married",classOf[Boolean])
    )

is better than

    val schema1=Schema(
            ("first",classOf[String]),
            ("last",classOf[String]),
            ("age",classOf[java.lang.Integer]),
            ("born",classOf[DateTime]),
            ("married",classOf[java.lang.Boolean])
    )

But in order to use this map
 
    private var serializers:Map[Class[_],Serializer[_]]=Map(
            (classOf[java.lang.Integer],IntegerSerializer.get),
            (classOf[java.lang.Double],DoubleSerializer.get),
            (classOf[java.lang.Boolean],BooleanSerializer.get),
            (classOf[DateTime],DateSerializer),
            (classOf[String],StringSerializer.get())
        )

to map "age" to IntegerSerializer, I need to somehow convert classOf[Int] to classOf[java.lang.Integer] .

I tried pattern matching like
(say v is Class[_])

v match {
        case c:Class[Int] => Class[java.lang.Integer]
      }

but I get

error: scrutinee is incompatible with pattern type;
found   : Class[Int]
required: java.lang.Class[_$12] where type _$12
case c:Class[Int] => Class[java.lang.Integer]

I suppose this is cause Class[Int] doesn't extend Class[_].

So, my initial question: Do you know how can I check if a v:Class[_] is Class[Int] or Class[Boolean]?

Thanks,

Kostas

Kevin Wright

unread,
Mar 3, 2011, 6:41:01 PM3/3/11
to Konstantine Kougios, scala...@googlegroups.com, Lex, Roland Kuhn

Does anything in here help you?

https://github.com/scalaj/scalaj-reflect/blob/master/src/main/scala/scalaj/reflect/TypeWrangler.scala

On 3 Mar 2011 23:22, "Konstantine Kougios" <kostas....@googlemail.com> wrote:
> Yes, null is one issue and I am using Option[] too. My idea was to treat
> AnyVals properly but if they are not different from their corresponding
> java wrapper classes, then I suppose I can use the java ones.
>
> Now I am facing a different issue. Do you know how can I convert a
> Class[_] to i.e. Class[Int] or Class[Boolean]? The problem is a bit
> complicated but let me try explaining:
>
> The syntax below
>
> val schema1=Schema(
> ("first",classOf[String]),
> ("last",classOf[String]),
> * ("age",classOf[Int]),*

> ("born",classOf[DateTime]),
> * ("married",classOf[Boolean])
> * )

>
> is better than
>
> val schema1=Schema(
> ("first",classOf[String]),
> ("last",classOf[String]),
> * ("age",classOf[java.lang.Integer]),
> * ("born",classOf[DateTime]),
> * ("married",classOf[java.lang.Boolean])
> * )

>
> But in order to use this map
>
> private var serializers:Map[Class[_],Serializer[_]]=Map(
> * (classOf[java.lang.Integer],IntegerSerializer.get),
> * (classOf[java.lang.Double],DoubleSerializer.get),
> * (classOf[java.lang.Boolean],BooleanSerializer.get),
> * (classOf[DateTime],DateSerializer),
>> wrote:
>>
>> Hi, that's what I am doing right now, but it is not 100% clean
>> solution when it comes to anything extending AnyVal. i.e. all Int
>> types are converted to java.lang.Integer. This means that my map
>> doesn't contain a value for it:
>>
>>
>> var serializers:Map[Class[_],Serializer[_]]=Map(
>> (*classOf[Int]*,IntSerializer),

Konstantine Kougios

unread,
Mar 4, 2011, 4:10:10 PM3/4/11
to Kevin Wright, scala...@googlegroups.com, Lex, Roland Kuhn
looks useful, when is it going to be released?

In the meantime I tried to recreate this functionality and after a couple of puzzling errors, I think I managed it:

  private val IntClass=classOf[Int]
  private val DoubleClass=classOf[Double]
  private val BooleanClass=classOf[Boolean]


  private def scalaToJ(c:Class[_]) = c match {
    case IntClass => classOf[java.lang.Integer]
    case DoubleClass => classOf[java.lang.Double]
    case BooleanClass => classOf[java.lang.Boolean]
    case x => x
  }


The puzzling errors were when my code was

  private val intClass=classOf[Int]
  private val doubleClass=classOf[Double]
  private val booleanClass=classOf[Boolean]


  private def scalaToJ(c:Class[_]) = c match {
    case intClass => classOf[java.lang.Integer]
    case doubleClass => classOf[java.lang.Double]
    case booleanClass => classOf[java.lang.Boolean]
    case x => x
  }

I was getting an error "unreachable code:    case doubleClass => classOf[java.lang.Double]"

Weird! Does scala treats vals with uppercase letter differently?

Cheers

Kevin Wright

unread,
Mar 4, 2011, 4:16:34 PM3/4/11
to Konstantine Kougios, scala...@googlegroups.com, Lex, Roland Kuhn


On 4 Mar 2011 21:10, "Konstantine Kougios" <kostas....@googlemail.com> wrote:
>
> looks useful, when is it going to be released?
>

Soon... But in a very fledgling form.

The code is all under the apache license though, so do feel free to copy & paste.

> In the meantime I tried to recreate this functionality and after a couple of puzzling errors, I think I managed it:
>
>   private val IntClass=classOf[Int]
>   private val DoubleClass=classOf[Double]
>   private val BooleanClass=classOf[Boolean]
>
>
>   private def scalaToJ(c:Class[_]) = c match {
>     case IntClass => classOf[java.lang.Integer]
>     case DoubleClass => classOf[java.lang.Double]
>     case BooleanClass => classOf[java.lang.Boolean]
>     case x => x
>   }
>
>
> The puzzling errors were when my code was
>
>   private val intClass=classOf[Int]
>   private val doubleClass=classOf[Double]
>   private val booleanClass=classOf[Boolean]
>
>
>   private def scalaToJ(c:Class[_]) = c match {
>     case intClass => classOf[java.lang.Integer]
>     case doubleClass => classOf[java.lang.Double]
>     case booleanClass => classOf[java.lang.Boolean]
>     case x => x
>   }
>
> I was getting an error "unreachable code:    case doubleClass => classOf[java.lang.Double]"
>
> Weird! Does scala treats vals with uppercase letter differently?
>

It does for pattern matching, though you can override that behavior by wrapping the name in `backticks`

Alex Cruise

unread,
Mar 4, 2011, 4:16:47 PM3/4/11
to Konstantine Kougios, scala...@googlegroups.com
On Fri, Mar 4, 2011 at 1:10 PM, Konstantine Kougios <kostas....@googlemail.com> wrote:
I was getting an error "unreachable code:    case doubleClass => classOf[java.lang.Double]"

Weird! Does scala treats vals with uppercase letter differently?

Yes! :)


You can either capitalize the identifiers, or quote the lower-case one with backticks, e.g. case `doubleClass` => ...
 
-0xe1a

Konstantine Kougios

unread,
Mar 4, 2011, 4:55:08 PM3/4/11
to Alex Cruise, scala...@googlegroups.com
I see, good to know, so I was just re-declaring variables in the local scope

Thanks
Reply all
Reply to author
Forward
0 new messages