- Concepts of Programming Languages

Strict and Nonstrict Evaluation

Instructor:

Learning Objectives

How much of an expression should be evaluated when computing a result?

  • Perform expression evaluation
  • Perform function calls and function argument evaluation

Strict and Nonstrict Operators

  • A strict construct evaluates all of its operands before it runs

Strict constructs

  • Arithmetic operators: +, -, ...
  • Comparison operators: <, <=, ...
  • Bitwise operators: |, &, ...
  • Function calls: f(x,y)

Non-strict constructs

  • e1 && e2: strict in e1, but not e2
  • e1 || e2: strict in e1, but not e2
  • if e1 then e2 else e3: strict in e1, but not e2 or e3

Conditional Expression

Conditional expression if e1 then e2 else e3

  • Evaluate e1; if true then evaluate e2, else evaluate e3
  1. for i <- 0 to 10 do
  2. print(i)
  3. if i % 2 == 0
  4. then println(": even")
  5. else println(": odd")
  6. end for

Conditionals in C

  • Conditional statement: executes return 1 or return n*..., never both
  1. int fact (int n) {
  2. if (n <= 1) {
  3. return 1;
  4. } else {
  5. return n * fact (n - 1);
  6. }
  7. }
  • Conditional expression: must be non-strict, otherwise non-terminating recursion
  1. int fact (int n) {
  2. return (n <= 1) ? 1 : n * fact (n - 1);
  3. }

What Happens?

  • Function calls are strict
  1. def f(b: Boolean, t: Unit, f: Unit) : Unit =
  2. if b then t else f
  3. for i <- 0 to 10 do
  4. print(i)
  5. f(i % 2 == 0,
  6. println(": even"),
  7. println(": odd"))
  8. end for
  • Both "even" and "odd" are printed every time f is invoked

What Happens?

  • Thunks: pass-by-name for explicit nonstrict evaluation of function arguments
  1. def f(b: Boolean, t: => Unit, f: => Unit) : Unit =
  2. if b then t else f
  3. for i <- 0 to 10 do
  4. print(i)
  5. f(i % 2 == 0,
  6. println(": even"),
  7. println(": odd"))
  8. end for
  • "even" and "odd" are printed again alternating

Call-By-Value: Scala

  1. def f(x: Double) : Double =
  2. val x1 = x
  3. val x2 = x
  4. x1 - x2
  5. end f
  6. println("f= " + f (Math.random())) // prints 0 (difference of same random Double)

Call-By-Value: Scala

  • Scala allows functions as parameters (no argument: delayed value = thunk)

Passing Functions in Scala

  1. def g(x: () => Double) : Double =
  2. val x1 = x()
  3. val x2 = x()
  4. x1 - x2
  5. end g
  6. // print difference of 2 random doubles
  7. println ("g= " + g (() => Math.random()))

Emulate in OOP (Java)

  1. interface java.util.function.Supplier<T> { T get(); }
  2. class GetRnd implements Supplier<Double> {
  3. public Double get() { return Math.random(); }
  4. }
  5. class Client {
  6. public static double g(Supplier<Double> t) {
  7. double x1 = t.get();
  8. double x2 = t.get();
  9. return x1-x2;
  10. }
  11. }
  12. // print difference of 2 random doubles
  13. System.out.println ("g= " + g (new GetRnd()));
  14. // functional notation without explicit class GetRnd
  15. System.out.println ("g= " + g (() -> Math.random()));

Call-By-Name: Scala

  • Scala has a special syntax for using thunks as parameters
  • Call-by-name parameters are non-strict

Thunks in Scala

  1. def h(x: => Double) : Double =
  2. // discouraged use of thunks
  3. val x1 = x
  4. val x2 = x
  5. x1 - x2
  6. end h
  7. // prints difference of 2 random doubles
  8. println ("h= " + h (Math.random()))

Call-By-Name: Scala

  • Curried call-by-name functions create new control constructs
    1. def myWhile (cond: => Boolean) (body: => Unit) : Unit =
    2. if (cond)
    3. body
    4. myWhile (cond) (body)
    5. end myWhile
  • Use (brackets {} or parentheses () are required)
    1. var i = 3
    2. myWhile (i > 0) {
    3. println ("i= " + i)
    4. i = i - 1
    5. }

Summary

Strict Evaluation

  • Evaluates all operands to determine value of an expression
    • Arithmetic operators etc.
    • Function arguments

Nonstrict Evaluation

  • Evaluates only necessary operands to determine value
    • Conditional expression
    • Shortcut evaluation of boolean expressions
  • Thunks: request explicit nonstrict evaluation of function arguments