Skip to content

Instantly share code, notes, and snippets.

@Sedose
Last active July 12, 2025 09:05
Show Gist options
  • Select an option

  • Save Sedose/febe6c2f0bc72071f354d551bdba42c3 to your computer and use it in GitHub Desktop.

Select an option

Save Sedose/febe6c2f0bc72071f354d551bdba42c3 to your computer and use it in GitHub Desktop.
Two Paradigms, One Algorithm: Expression-Oriented vs Imperative in Kotlin

Two Paradigms, One Algorithm: Expression-Oriented vs Imperative in Kotlin

Below are two structurally identical solutions for checking if one binary tree is a subtree of another. Only the control-flow style differs.


1. Expression-Oriented (Functional-Leaning)

class Solution {
    fun isSubtree(root: TreeNode?, subRoot: TreeNode?): Boolean =
        root != null && (                      // guard once
            root isIdenticalTo subRoot ||      // same tree here?
            isSubtree(root.left,  subRoot) ||  // …or in left branch?
            isSubtree(root.right, subRoot)     // …or in right branch?
        )

    private infix fun TreeNode?.isIdenticalTo(other: TreeNode?): Boolean =
        (this == null && other == null) ||
        (this != null && other != null &&
         this.`val` == other.`val` &&
         this.left  isIdenticalTo other.left &&
         this.right isIdenticalTo other.right)
}

2. Imperative (Guard-Clause Ladder)

class Solution {
    fun isSubtree(root: TreeNode?, subRoot: TreeNode?): Boolean {
        if (root == null) return false
        if (root isIdenticalTo subRoot) return true
        return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot)
    }

    private infix fun TreeNode?.isIdenticalTo(other: TreeNode?): Boolean {
        if (this == null && other == null) return true
        if (this == null || other == null) return false
        if (this.`val` != other.`val`) return false
        return this.left isIdenticalTo other.left &&
               this.right isIdenticalTo other.right
    }
}

Coding Paradigm Contrast

Axis Expression-Oriented Imperative
Primary construct Boolean expression, one = body whose value is computed. Statements & returns with if (...) return ....
Null guard Single guard (root != null && ...) wraps entire logic. First if (root == null) return false exits early.
Read flow Evaluates entire logic as a formula. Reads top-down like a checklist.
State/side-effects Pure value expression. Early returns organize logic into branches.
Debugging Harder to break mid-expression. Easy to insert logs and breakpoints.
Extensibility Add new checks inside the expression. Add new guard clauses explicitly.
Stylistic debt Denser; needs clear formatting. Verbose but very readable.
Mental model Algebraic equation = value. Checklist of rules.

Which to Pick?

Prefer Expression-Oriented when... Prefer Imperative when...
Team is comfortable with functional idioms. Team defaults to Java/Kotlin guard-clauses.
You want to match spec/pseudocode cleanly. You expect heavy logging or condition handling.
You prefer minimal return paths. You value step-by-step clarity.

Bottom line

Both solutions run in O(n) time and O(h) space. Your choice of style is about clarity for the reader, not performance.

Write for the next person reading your code—especially if that's you six months from now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment