When to use call-by-name and call-by-value?

后端 未结 5 1820
悲哀的现实
悲哀的现实 2021-02-03 13:15

I understand the basic concept of call-by-name and call-by-value, and I have also looked into handful number of examples. However, I am not very clear about when to use call-by-

5条回答
  •  说谎
    说谎 (楼主)
    2021-02-03 14:03

    There are plenty of places were call-by-name may gain performance or even correctness.

    Simple performance example: logging. Imagine an interface like this:

    trait Logger {
      def info(msg: => String)
      def warn(msg: => String)
      def error(msg: => String)
    }
    

    And then used like this:

    logger.info("Time spent on X: " + computeTimeSpent)
    

    If the info method doesn't do anything (because, say, the logging level was configured for higher than that), then computeTimeSpent never gets called, saving time. This happens a lot with loggers, where one often sees string manipulation which can be expensive relative to the tasks being logged.

    Correctness example: logic operators.

    You have probably seen code like this:

    if (ref != null && ref.isSomething)
    

    Say you declared && method like this:

    trait Boolean {
      def &&(other: Boolean): Boolean
    }
    

    then, whenever ref is null, you'll get an error because isSomething will be called on a null reference before being passed to &&. For this reason, the actual declaration is:

    trait Boolean {
      def &&(other: => Boolean): Boolean =
        if (this) other else this
    }
    

    So one may actually wonder is when to use call-by-value. In fact, in the Haskell programming language everything works similar to how call-by-name works (similar, but not the same).

    There are good reasons not to use call-by-name: it is slower, it creates more classes (meaning the program takes longer to load), it consumes more memory, and it is different enough that many have difficult reasoning about it.

提交回复
热议问题