Home > Software engineering >  How to pass extension function as argument?
How to pass extension function as argument?

Time:07-17

There is an extension functions

fun List<Track>.sortByTitle(): List<Track> {
    return this.sortedBy { it.title }
}

fun List<Track>.sortByArtist(): List<Track> {
    return this.sortedBy { it.artists[0].name }
}

What need to write in arguments of sort function in order to pass an extension function?

fun sortByTitle(owner: String, kind: String) {
    sort(owner, kind) // pass List<Track>.sortByTitle
}

fun sortByArtist(owner: String, kind: String) {
    sort(owner, kind) // pass List<Track>.sortByArtist
}

private fun sort(owner: String, kind: String) {
    val remote = playlist.get(owner, kind)
    val tracks = // call extension function: remote.tracks.sortByTitle()
    // ...
}

CodePudding user response:

We can pass functions using function types, for example:

fun sortByTitle(owner: String, kind: String) {
    sort(owner, kind, List<Track>::sortByTitle)
}

fun sortByArtist(owner: String, kind: String) {
    sort(owner, kind, List<Track>::sortByArtist)
}

private fun sort(owner: String, kind: String, sortStrategy: List<Track>.() -> List<Track>) {
    val remote = playlist.get(owner, kind)
    val tracks = remote.tracks.sortStrategy()
    // ...
}

In the above example List<Track>.() -> List<Track> means: function that is an extension over List<Track> and returns List<Track>.

CodePudding user response:

Not really sure, what you want to do there.

I'd suggest to use something like:

val theSortedList = listOfTracks.filter { it.title == "two" }.sortByArtist()

anyway, to pass an extension function as argument to another function and call it from there, here is some example code in your context:

fun List<Track>.sortByTitle(): List<Track> {
    return this.sortedBy { it.title }
}

fun List<Track>.sortByArtist(): List<Track> {
    return this.sortedBy { it.artists[0].name }
}

fun main() {
    println("sortByTitle")
    val titleTracks = sort("somebody", "somekind", List<Track>::sortByTitle)
    titleTracks.forEach { println("${it.title}: ${it.artists.map { it.name }.joinToString()}") }
    println()
    println("sortByArtist")
    val artistTracks = sort("somebody", "somekind", List<Track>::sortByArtist)
    artistTracks.forEach { println("${it.title}: ${it.artists.map { it.name }.joinToString()}") }
}

fun sort(owner: String, kind: String, function: List<Track>.() -> List<Track>): List<Track> {
    val listOfTracks = listOf<Track>(
        Track("two", listOf(Artist("Madonna"), Artist("Beethoven"))),
        Track("one", listOf(Artist("Prince"), Artist("Elvis"))),
    )
    var sortedTracks: List<Track>
    sortedTracks = function.invoke(listOfTracks)
    // another way to invoke the function:
    sortedTracks = listOfTracks.function()
    return sortedTracks
}

data class Playlist(val name: String) {
    fun get(artist: Artist, kind: String): List<Artist> = listOf()
    fun tracks(): List<Track> = listOf()
}
data class Track(val title: String, val artists: List<Artist>)
data class Artist(val name: String)
  • Related