Call by Value, Call by Name

Call by Value

  • 문자그대로 값을 호출하는 것

  • 즉, 함수가 Argument 로 전달되었을 경우에 전달된 그 함수를 즉시 평가 (함수의 수행)하는 것을 말한다.

fun main(args: Array<String>) {
    callByValue(funA)
}

fun callByValue(b: Boolean): Boolean {
    println("callByValue")
    b
}

fun funA(): Boolean {
    println("funA")
    true
}

// funA
// callByValue
b의 값을 사용하는것은 println("callByValue")의 이후이지만, 함수의 수행은 더 먼저되었다.
-> callByValue의 개념에 따라 함수가 Argument로 전달될때 그 즉시 평가되고
그 결과값이 메소드의 파라미터로 전달되기 때문.

Call by Name

  • Call by Value 와 다르게 함수가 함의 Argument 로 전달될때 바로 평가되지 않고, 파라미터로 전달된 함수가 실제로 호출이 되는 시점에 평가를 하는 개념.

//scala
object Main {

  def main(args: Array[String]): Unit = {
    callByName(funA)
  }

  def callByName(f : () => Boolean): Boolean = {
    println("callByName")
    f()
  }

  def funA(): Boolean = {
    println("funA")
    true
  }

}

//callByName
//funA

callByName 함수의 파라미터를 보면 f : () => Boolean 이라는 함수를 파라미터로 전달 받는다.

(callByValue에서는 b: Boolean 이라는 값을 전달받았다. callByValue에서는 Boolean값은 B 를 callByName에서는 실제 값이 아닌 함수를 파라미터로 전달받았다는 점이 가장 큰 차이. 또 println(“callByValue”) 에후에 f가 아닌 f()로 함수를 call 했다.)

callByName 은 funA() 가 argument 로 넘어간 시점이 아닌 f()가 call 되는 시점에 값이 평가된다.

그래서 이걸 어디에 쓰나요?

  • 리소스가 많이들고 시간도 많이드는 복잡한 연산을 하는 메소드 A 가 있다고 가정하자. 하지만 메소드 A 는 특정 조건에 따라 수행이 될 수도 있고, 수행 되지 않을 수도 있다.

object Main {

  def main(args: Array[String]): Unit = {
    val condition = false
    callByValue(condition, doSomething())
  }

  def doSomething(): Boolean = {

    println("something")
    // 오래걸리는 연산

    doSomething()
  }

  def callByValue(condition: Boolean, value: Boolean): Unit = {
    if (condition) {
      value
    }
  }
}

//something 반복

callByValue 의 경우 condition 이 true, false 상관이 모두 callByValue(condition, doSomething) 가 호출 될 때 doSomething() 을 평가 하게된다. 실제 코드는 condition 이 true 일 경우에만 호출됨에도 불구하고 doSomething 이 평가된다.

이런 코드의 경우 callByValue 방식은 condition 에 상관없이 평가 되기 때문에 매우 비효율적이다. 그렇다 callByName 은?

object Main {

  def main(args: Array[String]): Unit = {
    val condition = false
    callByName(condition, doSomething)
  }

  def doSomething(): Boolean = {

    println("something")
    // 오래걸리는 연산

    doSomething()
  }

  def callByName(condition: Boolean, f: () => Boolean): Unit = {
    if (condition) {
      f()
    }

    println("finish")
  }
}

//finish

condition 이 true 일 경우에는 callByValue 예제와 같이 무한 루프에 빠진다. 하지만 과정이 다르다. callByValue 와 다르게 argument 로 전달 될때는 평가되지 않고, 21번 째 라인 f() 에서 평가가 된다. condition 이 false 일 경우에는 f()를 평가하지 않는다. 때문에 무한 루프에 빠지지 않고 finish 가 정상적으로 출력된다.

Last updated