1

when I compile following code it failure and throw error:

MainTest.scala:11: error: missing argument list for method read in object MainTest

object GenericTest {

  def createStream[T: ClassTag](endpoint: String, shardId: Int, func: RecordEntry => T): DStream[T] = {
    null
  }

  def createStream[T: ClassTag](endpoint: String,func: RecordEntry => T): DStream[T] = {
    null
  }
}

object MainTest {

  def main(args: Array[String]): Unit = {
    val ddd = GenericTest.createStream[String]("6", 1, read)
  }

  def read(record: RecordEntry): String = {
    s"${record.getString(0)},${record.getString(1)}"
  }
}

If I remove the second method createStream in GenericTest, then MainTest can compile successfully. Or If I modify the MainTest as following(remove the "[String]" when call GenericTest.createStrem(xxx), it can compile successfully.

def main(args: Array[String]): Unit = {
    //remove the "[String]"
    val ddd = GenericTest.createStream("6", 1, read)
  }

Or if I modify the MainTest as following(add the red convert to func) it can compile successfully.

def main(args: Array[String]): Unit = {
    // add the " _" after read parameter
    val ddd = GenericTest.createStream[String]("6", 1, read _)
  }

Any idea about this issue, why it compile failure ? And what's the correct way should be like ?

nurseryboy
  • 13
  • 4

2 Answers2

1

Compile error says

Error:(25, 58) missing argument list for method read in object MainTest
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `read _` or `read(_)` instead of `read`.
      val ddd = GenericTest.createStream[String]("6", 1, read)

So please do either

val ddd = GenericTest.createStream[String]("6", 1, read _)

or

val ddd = GenericTest.createStream[String]("6", 1, read(_))
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • Thanks, yes this can solve the problem, but as mention in the question that even if don't use read _ or read(_), it also can compile successfully where there is only one createStrem method in Class GenericTest. I don't why it compile failure if GenericTest has two createStrem method. – nurseryboy Feb 22 '19 at 06:12
1

The error is caused by attempting to pass a method as a function. A method, such as read, is associated with an object so it can't be called as a bare function.

The expression read _ is called the eta expansion of read and it basically binds the MainTest object to the read method to create a bare function.

So you already have the correct way to do it in the last snippet of code in your question.


So why does it work without the _ if there is only one version of createStream?

The error message says:

Unapplied methods are only converted to functions when a function type is expected.

In other words, the compiler will automatically do this conversion if you pass a method when it knows it needs a function.

When there is a single version of createStream the compiler can match the supplied values with the arguments for that method. It knows that a function RecordEntry => T is required so it does the conversion (eta expansion) from a method to a function.

When there are multiple overloaded versions of createStream the compile must first determine which version is being called. It compares the number and types of the values with the number and types of the arguments for each version of createStream. In this case there is no match for func because the type is wrong: it is a method not a function. So when there are overloaded methods you must convert the method to the type required for the appropriate overloaded method to match.

Tim
  • 26,753
  • 2
  • 16
  • 29
  • Thanks, yes this can solve the problem, but as mention in the question that even if don't use read _ or read(_), it also can compile successfully where there is only one createStrem method in Class GenericTest. I don't why it compile failure if GenericTest has two createStrem method. – nurseryboy Feb 22 '19 at 06:12
  • 1
    @nurseryboy I have added an explanation of why it succeeds with a single `createStream` method. – Tim Feb 22 '19 at 08:27