Is there a typedef for functions?


#1

I'd like to pass in a function around as a listener, but I don't want to have to manually manage this function's signature in a multiple number of places. If I could typedef a function signature this would help out. In Java world I use an interface with a single function, a single abstract method, for this. I could pass instances of that interface around. I could do this with Kotlin too except in Java I can use an anonymous function in a function argument, like you can with a Runnable, but not for interfaces defined with Kotlin.

Someone suggested on IRC to use companion objects and functions in classes to achieve this, but that’s pretty verbose and even much less readable. This is a pretty big reason for me to not want to use Kotlin, but maybe I’m just doing this wrong?

To explain with code:

public interface Bar {
    fun runBar(stuff: Stuff): List<Result>
}

Then in my code somewhere it would be nice to just be like:

class Foo () {   runBar(bar: Bar) {   val results = bar.runBar(stuff)   }

}

And then somewhere else:

def foobar() {   runBar((stuff) -> {   val r = ArrayList<Result>()   ... //do stuff   return r   }) }

^^ this doesn’t seem possible, and that’s really, very much unfortunate.

Like not having a really easy way to pass functions around as arguments to other functions or as variables is a very undesirable thing. SAM’s make this trivial in Java 8, and in Kotlin it seems like you have to jump through hoops to do this. You either manage your function signatures manually all over the place or you create verbose classes or objects wherever you want to pass a function around.

EDIT

Someone indicated you could accomplish what I want this way:

interface Foo {   fun runFoo(bar: Bar) : BarData }

class Bar {
  public val bar: String = “bar”
}

class BarData {
  public val barData: Int = 1;
}

fun main(args: Array<String>) {
  test(object: Foo {
  override fun runFoo(bar: Bar) : BarData {
           return BarData()
  }
  })
}

fun test(foo: Foo) {
  val barData: BarData = foo.runFoo(Bar())
}

Which works, but it’s much more verbose than Java 8’s way. The call to test would be one line in Java 8, not 5.


Typedef for kotlin
#2

So someone else found this:

https://youtrack.jetbrains.com/issue/KT-7770 (which I commented on)

and there’s a discussion linked to here

Seems like there’s no desire to change or make passing functions around easier. :frowning:


#3

Kotlin supports SAM conversion in exactly the same way as Java. This will work:

test { BarData() }


#4

No it doesn't, try it. It only works if the interface was created in Java. Also did you see the issue?

https://youtrack.jetbrains.com/issue/KT-7770


#5

Just in case you didn't believe me:

http://try.kotlinlang.org/#/UserProjects/14tortgv098eblfn8qodv8ba4n/ps8da9ndt7ti9b46kgmtmseqb0


#6

There's no typedef for functions yet, but when it will come, it will likely be a true typedef and not a SAM definition:

typedef Listener = (Event) -> Unit

instead of

interface Listener {   fun notify(event: Event) }


#7

That would be awesome! Do you think that would be added before 1.0?


#8

This is very unlikely


#9

Oh ok, well just knowing you're considering it makes me pretty bullish for Kotlin! Until then I'll probably use Kotlin interfaces with the verbose object notation or write the interfaces in Java if I'm passing functions around to avoid managing the function singatures.


#10

It would be great if this feature was a more general typedef, e.g.

typedef Seconds = Int typedef Minutes = Int

fun sleep(time: Seconds) { … }

sleep(3)  // error
sleep(Minutes(2))  // error
sleep(Seconds(2))  // ok
sleep(2.seconds))  // automatically defined extension function


#11

Yes, and it's a very controversial topic in fact :) But I believe this can be done so that it covers all the relevant use cases


#12

Why not this way without interface:

class Bar {
  public val bar: String = “bar”
}

class BarData {
  public val barData: Int = 1;
}

fun main(args: Array<String>) {
  test { BarData() }
}

fun test(foo: (Bar) -> BarData) {
  val barData: BarData = foo(Bar())
}


#13

Because managing function signatures throughout all the places they are passed as function arguments and stored as variables is a very tedious exercise in function type hell. Imagine a verbose function signature that you have to painstakingly write out across many different parts of your app, and then later when you have to change it. Maybe you might suggest to not use verbose functions or not pass around or store functions so much, which is fine if that's the kind of language you want, but in my opinion it would make Kotlin an even less function friendly language than Java 8. Thankfully typedefs are being considered.


#14

Ok, you are right, I forgot about possible signature change of function literal. It seems to be critical feature for large projects. Moreover, it would eliminate boilerplate code. Currently I often use lambdas in primary constructors and I have to wrap it in multiple lines.


#15

Hi,

If you replace the interface with a class that accepts the function I think you achieve what you want.

class Foo(val f: (Bar) -> BarData)

class Bar {
  public val bar: String = “bar”
}

class BarData {
  public val barData: Int = 1;
}

fun main(args: Array<String>) {
  test(Foo { BarData() })
}

fun test(foo: Foo) {
  val barData: BarData = foo.f(Bar())
}


Cheers,
Andrew


#16

Yes that's a great idea. Thank you. :)


#17

I would prefer it if there were both kinds of typedefs, one for synonyms and one for new types:

type Text = Array<String> // alias

newtype Yen = Int // incompatible

val budget: Yen = Yen(8000)

val flyer = arrayOf("You can trade","Easy!"))

fun sellForDollars(yen: Yen, dollars: Int, comment: Text) {

  ...

}

sellForDollars(budget, 10, flyer)   // ok

sellForDollars(Yen(1000), 9, arrayOf("Hm."))   //ok

sellForDollars(10, 10, flyer)           // error, Int is not Yen

sellForDollars(Yen(10), Yen(10), flyer)           // error, Yen is not Int

sellForDollars(10, Yen(10), flyer)           // error

type Predicate<T> = (T) -> Bool


#18

You can even add `invoke` function to the class :)

class Foo(val f: (Bar) -> BarData) { fun invoke(bar: Bar) = f(bar) }
And then just call the instance of the class:
fun test(foo: Foo) {
    val barData: BarData = foo(Bar())
}

#19

Wow, that's pretty much a type definition for a function right there. You know I've seen invoke mention twice in all the pages in the documentation:

http://kotlinlang.org/docs/reference/annotations.html

http://kotlinlang.org/docs/reference/operator-overloading.html

But never is it explained what it does or how it’s used unless I’m just blind. Is this a problem with the documentation? I’m just not seeing it anywhere.


#20

The docs are in my experience one of the easiest/highest impact places to be an open source contributor to Kotlin. There's even a handy edit button. So if you can think of a way to improve them, go for it.

Not many languages let you define a call operator overload. C++ is one of them. A class that overrides the call/invoke operator in C++ is usually called a Functor. There’s a discussion of when you may wish to use such a thing here:

  http://stackoverflow.com/questions/317450/why-override-operator

However it’s not helpful for Kotlin developers. The thing to realise is that C++ does not have anonymous inner classes in the same way as you get on the JVM. Functors give the same effect though: you can define a thing that acts like a function but which has associated permanent state.

Kotlin has lambdas with capturing, anonymous inner classes AND ability to create “functors”. So I guess in Kotlin we’ll find some other use for overloading operator invoke. Probably useful not only for working around language limitations, but also DSL stuff.