rainman
rainman

Reputation: 13

Kotlin Lambda not calling code inside

I encountered the strangest thing.

Lets say I have a text file called "lines.txt". This file contains lines in key value pairs.

test:100
test1:200
test2:300
test3:400

If I read this file in Kotlin the list is not empty however the loop inside the output stream does not get called.

object App {

@JvmStatic
fun main(args: Array<String>) {

    // file containing lines of text
    val lines = Files.readAllLines(Paths.get("./hashes.txt"))

    // not empty
    println(lines.size)

    // write back a modified version
    PrintWriter(FileWriter(File("./lines2.txt"))).use { out -> {

            // this doesn't get called
            println(lines.size)
            lines.forEach {
                out.println(it.split(":")[0])
            }

        }
    }

}

}

I don't understand why this is so if anyone can enlighten me that would be awesome.

Upvotes: 1

Views: 834

Answers (2)

Willi Mentzel
Willi Mentzel

Reputation: 29844

guenther already told you what is wrong with your code, but I think an explanation of what happened is missing.

Consider the following:

val x = { println("y") }

Will it print out y? No, the lamda is never invoked. You have to call x().

Let's take a look at what you did:

val x = { { println("y") } }
x()

Will it print out y? No, because you don't invoke the lambda that prints y.

To make things more clear, let's specify the types explicitely.

val x:() -> (() -> Unit) = { { println("y") } }

Now we can see that the first lambda invoked by x() returns a lambda as well so you would have to call x()() in order to invoke the returned lambda as well.

So using a second pair a curly braces is not just not optional but gives the code a whole new meaning.


But this means that there would be also another solution to your problem.

PrintWriter(FileWriter(File("./lines2.txt"))).use { out -> {
        println(lines.size)
        lines.forEach {
            out.println(it.split(":")[0])
        }
    }() // <-- add braces here to invoke the lambda
}

So, you can either remove two brackets are add two more. Choice is yours.

Disclaimer: Removing two braces is the way to go. The other option is just to prove a point.

Upvotes: 2

guenhter
guenhter

Reputation: 12167

The list is not empty. A single println(lines.size) will shown you that, because that println is never called.

You simply have one pair of curly braces too much.

change your code to

   ...
   PrintWriter(FileWriter(File("./lines2.txt"))).use { out ->

        // list is empty??
        println(lines.size)
        lines.forEach {
            out.println(it.split(":")[0])
        }
    }
    ...

The reason is, that a lambda doesn't need its block in curly braces.

So don't write

out -> { ... }

just write

out -> ...

Upvotes: 2

Related Questions