3

I don't know why the following code can not compile, this is the error message:

Error:(29, 7) no type parameters for method flatMap: (f: String => Option[B])Option[B] exist so that it can be applied to arguments (String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec })
--- because ---
argument expression's type is not compatible with formal parameter type; found : String => Some[Class[?0]] forSome { type ?0 <: org.apache.hadoop.io.compress.CompressionCodec }
required: String => Option[?B]
a.flatMap(codecClassName => {
^

and code

  def f(a: Option[String]): Unit = {
    a.flatMap(codecClassName => {
      val codecFactory = new CompressionCodecFactory(new Configuration())
      val codecClass = codecFactory.getCodecClassByName(codecClassName)
      if (codecClass == null) {
        throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
      }
      Some(codecClass)
    })
  }
Filburt
  • 17,626
  • 12
  • 64
  • 115
zjffdu
  • 25,496
  • 45
  • 109
  • 159

2 Answers2

2

This seems to be related to the fact that getClass and classOf are not returning the exact same thing. See Scala equivalent of Java java.lang.Class<T> Object for more details.

Looking around for a workaround I came across Scala Getting class type from string representation.

So how about:

val codecClass = Manifest.classType(codecFactory.getCodecClassByName(codecClassName))
Community
  • 1
  • 1
Dennis Hunziker
  • 1,293
  • 10
  • 19
  • Thanks, it works, but I still could not understand why I can not use getClass, even it is different from classOf, but I didn't mix them. – zjffdu Feb 02 '16 at 12:54
0

This should work. flatMap involves both map and flatten, so it may need more type annotations in some cases. The overall code works after annotation of the function parameter, i.e. (codecClassName: String).

Note the other change -- that flatMap with an inner function returning an Option type is the same as a map if that function returns what's inside the Option (i.e. flattens the option) (see below).

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.io.compress.{CompressionCodec, CompressionCodecFactory}
...
  def f(a: Option[String]): Option[Class[_ <: CompressionCodec]] = {
    a.map((codecClassName: String) => {
      val codecFactory = new CompressionCodecFactory(new Configuration())
      val codecClass   = codecFactory.getCodecClassByName(codecClassName)
      if (codecClass == null) {
        throw new RuntimeException("Unknown or not supported codec:" + codecClassName)
      }
      codecClass
    })
  }

To show the relationship between flatMap and map as described above:

scala> val opt: Option[Int] = Some(1)
opt: Option[Int] = Some(1)

scala> opt.map((i: Int) => i + 1)
res0: Option[Int] = Some(2)

scala> val opt2: Option[Int] = None
opt2: Option[Int] = None

scala> opt.flatMap((i: Int) => Some(i + 1))
res1: Option[Int] = Some(2)

scala> opt2.map((i: Int) => i + 1)
res3: Option[Int] = None

scala> opt2.flatMap((i: Int) => Some(i + 1))
res2: Option[Int] = None
ELinda
  • 2,658
  • 1
  • 10
  • 9