328

Given function foo :

fun foo(m: String, bar: (m: String) -> Unit) {
    bar(m)
}

We can do:

foo("a message", { println("this is a message: $it") } )
//or 
foo("a message")  { println("this is a message: $it") }

Now, lets say we have the following function:

fun buz(m: String) {
   println("another message: $m")
}

Is there a way I can pass "buz" as a parameter to "foo" ? Something like:

foo("a message", buz)
Scooter
  • 6,802
  • 8
  • 41
  • 64
mhshams
  • 16,384
  • 17
  • 55
  • 65

11 Answers11

483

Use :: to signify a function reference, and then:

fun foo(msg: String, bar: (input: String) -> Unit) {
    bar(msg)
}

// my function to pass into the other
fun buz(input: String) {
    println("another message: $input")
}

// someone passing buz into foo
fun something() {
    foo("hi", ::buz)
}

Since Kotlin 1.1 you can now use functions that are class members ("Bound Callable References"), by prefixing the function reference operator with the instance:

foo("hi", OtherClass()::buz)

foo("hi", thatOtherThing::buz)

foo("hi", this::buz)
Jayson Minard
  • 84,842
  • 38
  • 184
  • 227
  • 14
    A member reference can be passed around but that would be a 2 parameter function in this case with the first parameter requiring an instance of the class. A better way is to wrap the member function with a lambda that closed on the class. Assuming all of the above was in a class: `fun something() { foo("hi", { buz(it) }) }` – Jayson Minard Dec 25 '15 at 14:31
  • is there anyway to do this if buz is generic and type inference fails? – jk. Aug 18 '16 at 21:45
  • 2
    It seem that functions that do belong to a class can be passed in if you are operating within the same class, as of kotlin 1.1 you can do it with `this::function` – Joe Maher Apr 10 '17 at 05:51
  • 1
    In addition, if you would like to make the function parameter nullable, just wrap the type declaration in parentheses with a question mark at the end. e.g. `bar: ((m: String) -> Unit)?` – Aba Mar 22 '18 at 02:10
  • why are both parameters of foo named 'm'? – Marty Miller Sep 29 '18 at 01:23
  • 1
    @MartyMiller they are not. The parameter `m` is for foo, the other parameter is the parameter name of the function type passed in variable bar to the function. – Jayson Minard Sep 29 '18 at 04:32
  • @TylerPfaff There is a parameter passed within the call when it is the variable `bar` ... are you wanting to curry a parameter? See this here: https://github.com/MarioAriasC/funKTionale/wiki/Currying Or ask another question in Stack Overflow with your specific example, because I'm not sure what you are asking. – Jayson Minard Mar 21 '19 at 01:26
  • Thank you! I spent hours trying to find this information. The kotlin websites aren't helpful when it comes to real examples. – SMBiggs Jan 18 '20 at 03:31
  • Else you can add ```inline``` keyword to the function that will make your code work better – Youn Tivoli Aug 12 '20 at 14:40
  • This is a bit confusing for me. So in the above code, who's passing the argument m: String for the function buz(m: String). It's used by something() function, but I don't see anyone passing arguments for buz? – capt.swag Nov 21 '20 at 18:10
  • @capt.swag the call in `something()` to `foo` passes in a reference to `buz` which is received as the parameter `bar`, so then the call to `bar` is actually calling `buz` for this one call stack and it is forwarding the `m` parameter to that reference to `buz`. – Jayson Minard Dec 01 '20 at 19:19
  • So because Java is a LISP 2, the JVM really wants to be, and so Kotlin is a LISP 2 as well Ok, I can work with that. Just need to remember when switching to / fro JS, which is a LISP 1 :) – yeoman May 07 '23 at 14:17
29

About the member function as parameter:

  1. Kotlin class doesn't support static member function, so the member function can't be invoked like: Operator::add(5, 4)
  2. Therefore, the member function can't be used as same as the First-class function.
  3. A useful approach is to wrap the function with a lambda. It isn't elegant but at least it is working.

code:

class Operator {
    fun add(a: Int, b: Int) = a + b
    fun inc(a: Int) = a + 1
}

fun calc(a: Int, b: Int, opr: (Int, Int) -> Int) = opr(a, b)
fun calc(a: Int, opr: (Int) -> Int) = opr(a)

fun main(args: Array<String>) {
    calc(1, 2, { a, b -> Operator().add(a, b) })
    calc(1, { Operator().inc(it) })
}
Rui Zhou
  • 309
  • 4
  • 5
  • 9
    In current Kotlin, you now *can* use a member function as a reference. You should now update this answer. – Jayson Minard Apr 16 '17 at 14:19
  • By defining functions in the companion object calling code get a bit better and no new instance of Operator get created every time. This would look like a static fun in Java – C.A.B. Feb 20 '18 at 04:36
  • Great solution, this is the only way I found that works when the function is in a class. I don't consider it ugly but beautiful, almost looks like an angular template variable but for code. – gunslingor Apr 05 '20 at 21:11
28

Just use "::" before method name

fun foo(function: () -> (Unit)) {
   function()
}

fun bar() {
    println("Hello World")
}

foo(::bar) Output : Hello World

erluxman
  • 18,155
  • 20
  • 92
  • 126
8

Kotlin 1.1

use :: to reference method.

like

    foo(::buz) // calling buz here

    fun buz() {
        println("i am called")
    }
7

If you want to pass setter and getter methods.

private fun setData(setValue: (Int) -> Unit, getValue: () -> (Int)) {
    val oldValue = getValue()
    val newValue = oldValue * 2
    setValue(newValue)
}

Usage:

private var width: Int = 1

setData({ width = it }, { width })
CoolMind
  • 26,736
  • 15
  • 188
  • 224
3

Here is simple example where I pass the multiplication function as parameter to another function.

fun main(){
    result(10,3,::multiplication)// pass function as parameter wow kotlin amazing
}
fun multiplication(first:Int,second:Int):Int{
    return first*second
}
fun result(firstOne:Int,secondOne: Int,fn:(Int,Int)->Int){
    val result=fn(firstOne,secondOne)
    print(result)

}
Anwar Zahid
  • 227
  • 3
  • 10
2

Jason Minard's answer is a good one. This could also be achieved using a lambda.

fun foo(m: String, bar: (m: String) -> Unit) {
    bar(m)
}

val buz = { m: String ->
    println("another message: $m")
}

Which can be called with foo("a message", buz).

You can also make this a bit more DRY by using a typealias.

typealias qux = (m: String) -> Unit

fun foo(m: String, bar: qux) {
    bar(m)
}

val buz: qux = { m ->
    println("another message: $m")
}
flesk
  • 7,439
  • 4
  • 24
  • 33
1

apparently this is not supported yet.

more info:

http://devnet.jetbrains.com/message/5485180#5485180

http://youtrack.jetbrains.com/issue/KT-1183

mhshams
  • 16,384
  • 17
  • 55
  • 65
1

You can also do this inline using a lambda if that is the only place you are using that function

fun foo(m: String, bar: (m: String) -> Unit) {
    bar(m)
}

foo("a message") {
    m: String -> println("another message: $m")
}
//Outputs: another message: a message
kooskoos
  • 4,622
  • 1
  • 12
  • 29
0

Another example:

 fun foo(x:Int, Multiply: (Int) -> (Int)) {
    println(Multiply(x))
 }
 fun bar(x:Int):Int{
    return  x * x
 }
 foo(10, ::bar)
Erik K.
  • 1,024
  • 12
  • 13
-9

First-class functions are currently not supported in Kotlin. There's been debate about whether this would be a good feature to add. I personally think they should.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
ajselvig
  • 688
  • 1
  • 5
  • 12