JackieNim f597fc1b07
fix: Fixed pages showing up in wrong language (#1752)
* Fix languages

* Missed change for version number

* Add language field for presentation

* Revert change in README for double buffer

Co-authored-by: Jackie Nim <=>
2021-05-19 19:49:05 +03:00
..

layout, title, folder, permalink, categories, language, tags
layout title folder permalink categories language tags
pattern Trampoline trampoline /patterns/trampoline/ Behavioral en
Performance

Intent

Trampoline pattern is used for implementing algorithms recursively in Java without blowing the stack and to interleave the execution of functions without hard coding them together.

Explanation

Recursion is a frequently adopted technique for solving algorithmic problems in a divide and conquer style. For example calculating fibonacci accumulating sum and factorials. In these kinds of problems recursion is more straightforward than their loop counterpart. Furthermore recursion may need less code and looks more concise. There is a saying that every recursion problem can be solved using a loop with the cost of writing code that is more difficult to understand.

However recursion type solutions have one big caveat. For each recursive call it typically needs an intermediate value stored and there is a limited amount of stack memory available. Running out of stack memory creates a stack overflow error and halts the program execution.

Trampoline pattern is a trick that allows us define recursive algorithms in Java without blowing the stack.

Real world example

A recursive Fibonacci calculation without the stack overflow problem using the Trampoline pattern.

In plain words

Trampoline pattern allows recursion without running out of stack memory.

Wikipedia says

In Java, trampoline refers to using reflection to avoid using inner classes, for example in event listeners. The time overhead of a reflection call is traded for the space overhead of an inner class. Trampolines in Java usually involve the creation of a GenericListener to pass events to an outer class.

Programmatic Example

Here's the Trampoline implementation in Java.

When get is called on the returned Trampoline, internally it will iterate calling jump on the returned Trampoline as long as the concrete instance returned is Trampoline, stopping once the returned instance is done.

public interface Trampoline<T> {

  T get();

  default Trampoline<T> jump() {
    return this;
  }

  default T result() {
    return get();
  }

  default boolean complete() {
    return true;
  }

  static <T> Trampoline<T> done(final T result) {
    return () -> result;
  }

  static <T> Trampoline<T> more(final Trampoline<Trampoline<T>> trampoline) {
    return new Trampoline<T>() {
      @Override
      public boolean complete() {
        return false;
      }

      @Override
      public Trampoline<T> jump() {
        return trampoline.result();
      }

      @Override
      public T get() {
        return trampoline(this);
      }

      T trampoline(final Trampoline<T> trampoline) {
        return Stream.iterate(trampoline, Trampoline::jump)
            .filter(Trampoline::complete)
            .findFirst()
            .map(Trampoline::result)
            .orElseThrow();
      }
    };
  }
}

Using the Trampoline to get Fibonacci values.

  public static Trampoline<Integer> loop(int times, int prod) {
    if (times == 0) {
      return Trampoline.done(prod);
    } else {
      return Trampoline.more(() -> loop(times - 1, prod * times));
    }
  }
  
  log.info("start pattern");
  var result = loop(10, 1).result();
  log.info("result {}", result);

Program output:

start pattern
result 3628800

Class diagram

alt text

Applicability

Use the Trampoline pattern when

  • For implementing tail recursive function. This pattern allows to switch on a stackless operation.
  • For interleaving the execution of two or more functions on the same thread.

Known uses

Credits