I read the documentation for a long time, but did not fully understand how it works.

The inner voice whispers that these two lines should do the same thing:

private fun makePost(post: Map<String, String>): RequestBody { val body = FormBody.Builder() 1: post.forEach { (k, v) -> body.add(k, v) } 2: post.forEach { body::add } return body.build() } 

But do not. The first works, and the second does not (body remains empty, but there are no errors)

please explain where my inner voice screwed up and is it possible (how?) to use the function reference here?

  • You can ask the version of Kotlin , what do you use? - Eugene Krivenja
  • @EugeneKrivenja latest, which plugin in android studio pulls up. 1.1.2-3 - rjhdby
  • Are you build.gradle that this version is in build.gradle ? Plugin plugin, and suddenly not pull up? :) - Eugene Krivenja
  • @EugeneKrivenja of course sure. ext.kotlin_version = '1.1.2-3' , classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" ? compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" - rjhdby
  • Your inner voice is right, in my opinion, see the answer. - Eugene Krivenja

2 answers 2

Great, that with the version everything is clear. Here is my explanation:

The forEach method for your Map operates with Map.Entry<String, String> elements, and this is not the same as the two String parameters required by the body::add method.
But Kotlin instead of scolding, pretends to be able to expand the element, as it does in option number 1, but something does not work.

I think you can report a bug to them. At least that there is no error, no warning, but the code does not work.

Here is a link to the implementation of this feature.
https://youtrack.jetbrains.com/issue/KT-6947

This is similar to the specific case for Map , which was missed in the tests of the new feature.

  • Developer response: Your code is incorrect. To pass a method reference to a function, you need to enclose it in parentheses, not in curly braces: bar.forEach(foo1::add) Your code is incorrect. To pass a method reference to a function, you need to enclose it in parentheses, not in curly braces: bar.forEach(foo1::add) - rjhdby
  • Anyway, this is a bug, post.forEach { body::add } should not compile then. - Eugene Krivenja
  • In fact, this is a completely normal behavior of the language, misleading by the non-obvious syntax. In fact, a lambda doing nothing is created - rjhdby
  • Great, we 'll check in 1.1.3 :) - Eugene Krivenja

Developer response:

Your code is incorrect. It is not necessary to enclose it in parentheses, not in curly braces: bar.forEach (foo1 :: add)

When transferring (method) a function reference to a function, you must use regular brackets, not curly ones.

The following three lines do the same thing:

 post.forEach ({ (k, v) -> body.add(k, v) }) post.forEach { (k, v) -> body.add(k, v) } post.forEach (body::add) 

Please note that the referenced method must return Unit , otherwise it will not even compile.

If the only parameter is lambda, then ordinary brackets can be omitted and only curly lines (lines 1 and 2) should be left.

  • Interesting. Is it not known how braces are interpreted in this case? - yeputons
  • @yeputons updated the answer - rjhdby