1

I have the following sample code:

def transferFiles(files: List[String], move: Boolean = false ): Unit = {
    for(file <- files) {
        if (move) {
            println(s"Move $file")
        } else {
            println(s"Copy $file")
        }
    }
}

val files = List("autoexec.bat", "config.sys")
transferFiles(files)

This will print as expected:

Copy autoexec.bat
Copy config.sys

I would like to optimize it to be in a fashion similar to

def transferFiles(files: List[String], move: Boolean = false ): Unit = {
    def transfer = () => {
        println("Checking flag")
        if (move) {
            (file: String) => println(s"Move $file")
        } else {
            (file: String) => println(s"Copy $file")
        }       
    }
    for(file <- files) {
        transfer()(file)
    }
}

val files = List("autoexec.bat", "config.sys")
transferFiles(files)

which prints:

Checking flag
Copy autoexec.bat
Checking flag
Copy config.sys

The thing is that I want to see Checking flag only once and I don't want to call the function with double parentheses transfer()(file). I believe Higher Order functions can be used for this purpose, but I do not know how to make it work. Is anyone able to patch my code so that it fulfils at least the first requirement (only one print of the flag checking)?

Interfector
  • 1,868
  • 1
  • 23
  • 43
  • 4
    replace `def transfer = () => {` with `val transfer = {` and `transfer()(file)` with `transfer(file)`. See [this answer](http://stackoverflow.com/questions/18887264/what-is-the-difference-between-def-and-val-to-define-a-function/18887341#18887341) for details. – senia May 28 '15 at 08:10
  • @senia That is awesome, please add it as an answer – Interfector May 28 '15 at 08:29
  • I've added some explanations as answer. – senia May 28 '15 at 08:51

3 Answers3

1
def transferFiles(files: List[String], move: Boolean = false ): Unit = {
    val action = if(move) {
        println("Checking flag")
        (file: String) => println(s"Move $file")
    } else {
        println("Checking flag")
        (file: String) => println(s"Copy $file")
    }
    for(file <- files)
        action(file)
}

But I'd recommend this instead

def transferFiles(files: List[String], move: Boolean = false ): Unit = {
    if(move) {
        println("Checking flag")
        doFiles(files, file => println(s"Move $file"))
    } else {
        println("Checking flag")
        doFiles(files, file => println(s"Copy $file"))
    }
}

def doFiles(files: List[String], action: String => Unit ): Unit = {
    for(file <- files)
        action(file)
}
Interfector
  • 1,868
  • 1
  • 23
  • 43
dcastro
  • 66,540
  • 21
  • 145
  • 155
1

def transfer is a method without parameters that returns function without parameters that returns function. You could call it once and save result in variable like this:

def transfer = () => { ... }
val transferMethodResult = transfer
val transferFunctionResult = transferMethodResult()
for(file <- files) {
    transferFunctionResult(file)
}

You could replace def transfer with val transfer since you don't need method. See this answer for details.

val transfer = () => { ... }
val transferFunctionResult = transfer()
for(file <- files) {
    transferFunctionResult(file)
}

Now you have function without parameters that returns actual function. You don't need this function, you could evaluate it's body "in place" as code block to get actual transfer function:

val transfer = {
    println("Checking flag")
    if (move) {
        (file: String) => println(s"Move $file")
    } else {
        (file: String) => println(s"Copy $file")
    }       
}
for(file <- files) {
    transfer(file)
}

Now you have a code block ({...}). You don't need this code block, you need it's result. You could just assign last expression of this code block ("result expression") to variable like this:

println("Checking flag")

val transfer =
    if (move) {
        (file: String) => println(s"Move $file")
    } else {
        (file: String) => println(s"Copy $file")
    }       
for(file <- files) {
    transfer(file)
}

In general if you have val a = { expr1; expr2; ... exprN; resExpr} you could replace it with expr1; expr2; ... exprN; val a = resExpr.

Community
  • 1
  • 1
senia
  • 37,745
  • 4
  • 88
  • 129
  • @Interfector: If you have `val a = { expr1; expr2; ... exprN; resExpr}` you could replace it with `expr1; expr2; ... exprN; val a = resExpr`. – senia May 28 '15 at 09:17
  • The point of my edit was to show that the comparison is indeed executed only once. – Interfector May 28 '15 at 09:20
0

I see your problem, how about this solution? You could make a simple inner function and print the checking only once before transfering.

def transferFiles(files: List[String], move: Boolean = false ): Unit = {
    def transfer(file: String): Unit = {
        if (move) {
            println("Move $file")
        } else {
            println("Copy $file")
        }       
    }
    println("Checking flag")
    for(file <- files) {
        transfer(file)
    }
}

val files = List("autoexec.bat", "config.sys")
transferFiles(files)
Rofgar
  • 318
  • 3
  • 12
  • The `println("Checking flag")` was more of an indicator for redundant flag comparison. I am not bothered by the `println` per say :). I am looking for some code that can actually help do the comparison only once. – Interfector May 28 '15 at 08:25