user_s user_s - 27 days ago 7
Scala Question

Scala flatMap over getConstructors method (reflection)

I'm trying to iterate over the constructors of a given class using reflection.
The problem is that I need to do something to each element and then return only the ones that matches some predicate. the following code throws exception

classOf[String].getConstructors.flatMap(x=> doSomething(x); if(predicate(x)) Some(x) else None)


The exception:

argument expression's type is not compatible with formal parameter type;
found : java.lang.reflect.Constructor[_] => Iterable[java.lang.reflect.Constructor[?0(in value $anonfun)]] forSome { type ?0(in value $anonfun) }
required: java.lang.reflect.Constructor[_] => scala.collection.GenTraversableOnce[?B]


I'm not sure if this can be done with for comprehension because I need to call do something on each element(not just for the ones that holds the predicate):

for{
x <- c.getConsturctors
//doSomething(x) ??
if predicate(x)
}yield{
//doSomething(x) - only for the ones that holds the predicate
x
}


Calling c.getMethods works so I'm guessing it has something to do with the return type(Array[Methods] vs Array[Constructor[_]])...?

Answer :

flatMap - Alexey Romanov answer

for comprehension(with the help of pamu):

for{
x <- c.getConsturctors
_ = doSomething(x)
if predicate(x)
}yield x

Answer

Due to details of type inference implementation, Scala ends up with Iterable[java.lang.reflect.Constructor[A]] forSome { type A } where you want Iterable[java.lang.reflect.Constructor[A] forSome { type A }] (or shorter, Iterable[java.lang.reflect.Constructor[_]]). Annotating the type should work:

c.getConstructors.flatMap { x =>
  doSomething(x)
  (if (predicate(x)) Some(x) else None): Option[Constructor[_]]
}

but I must admit I don't see why the problem arises.