Arun Pandian M

Arun Pandian M

Android Dev | Full-Stack & AI Learner

From Nothing to Arrows: Objects and Simple Graphs

“Every complex system that works evolved from a simple system that worked.” — John Gall

Category theory doesn’t begin with abstractions or equations. It begins much like programming itself: with nothing… and then with arrows.

Before we talk about fancy ideas like functors or monads, we need to understand how structure is born.

A Small Story: Starting from Nothing

Imagine opening a brand-new Kotlin project for the first time.

No files. No classes. No functions.

Just a silent editor and a blinking cursor.

At first, it feels useless — there’s nothing to run, nothing to test, nothing to debug. And yet, that emptiness is not chaos. It’s valid. The compiler isn’t confused. The IDE isn’t broken. The project exists, even though it does nothing.

That “nothing” is not an error — it’s a starting point.

In Kotlin, and in good system design in general, emptiness is often intentional. It represents a state where nothing can happen yet, but also nothing can go wrong. No invalid states, no surprises, no side effects. Just a clean, well-defined beginning.

This is the same idea behind Kotlin’s Nothing type and category theory’s empty category: a space with no values, no paths, and no behavior — yet one that fits perfectly into the system’s rules.

Before we build arrows, before we compose functions, before we move data around, we begin here — with nothing. And from that quiet place, structure emerges.

1. No Objects — When Nothing Is Still Valid

https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/empty_category.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260225%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260225T014824Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=388b7f3785057632946a80de8f07215ae34fa26726a0189c509a67ba912f71a45e909cc55dc327bb71be549be3ef42ac6ee04fb2ffbd6dc068f656d24e8a07c74b63f044172342945f12b87e7a073aa9d1202f62ec94b11c431ce0c0a7996562c385c76453fe3b02e5684d79f1c3a04e88c618b825a16978d6138c2ef5ffa3cb434d778b69fa85822f4978bcdd886020983f8cb1b2c13d3c104f9e9c13ee2f39355eda63fb8f8ce9cd570b1b2420d223bab3e70defb886146da5e6beb2bf990680126ddb987109bc41a18dc071e0fa7039bd565e986994e13b5aa8a561ac2b6dd727108c45246a68acb8d56a0b5cc3804ead4e052578629199912fcc8bb7e8cf

In category theory, there exists something called the empty category.

It has:

  • no objects
  • no arrows (morphisms)
  • At first, this sounds useless. But as programmers, we already rely on this idea every day.

    Kotlin already understands “nothing”

    val users = emptyList<User>()

    This list:

  • contains no elements
  • crashes nothing
  • behaves correctly everywhere
  • It’s not an error — it’s a base case.

    Kotlin even has a type that represents impossibility:

    fun fail(message: String): Nothing =
        throw IllegalStateException(message)

    Nothing has:

  • no values
  • no instances
  • yet fits perfectly into the type system
  • The empty category plays the same role:

    It exists so the system is complete, not because it does something.

    Why category theory allows this

    Category laws say:

  • every object must have an identity
  • arrows must compose
  • If there are no objects, there is:

  • no missing identity
  • no broken composition
  • All rules are satisfied vacuously.

    Just like an empty loop:

    for (x in emptyList<Int>()) {
        // never runs, never breaks
    }

    2. Simple Graphs — When Structure Appears

    Now let’s add just a little something.

    Imagine this:

    A → B → C

    This is a directed graph:

  • nodes (A, B, C)
  • arrows between them
  • At this stage, it’s not yet a category. It’s just potential.

    How a Graph Becomes a Category (Naturally)

    Category theory doesn’t ask you to invent new behavior. It asks you to accept what is unavoidable.

    Step 1: Identity — “Stay where you are”

    Every object must be able to do nothing.

    So we add:

    A → A
    B → B
    C → C

    In Kotlin, this is the identity function:

    fun <T> id(value: T): T = value

    You almost never write it — but it’s always there.

    Step 2: Composition — “If it chains, it exists”

    https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/composition_path.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260225%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260225T014824Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=4ad52035c7c2b3e5f7e3e41637020464c06ab0be81aebde575b4f20b35dc3478cefb768c8c85f97a474411ad96f383a41a70570785e39bcd2a31a585c392ac624b2df589fc26ab14adeee7af8f1a8722623681cd950bfacceb7840b3454ebf4c7591673458619c5abe4fb533fb0214fcd9b5b0a3a5f80a314cb7caf9a3a8aafc4b289d0d83ebee7d527c989058bdef413ae73092ebe958445952b2d77ddcfcd3d85de928f32cd03a9011f2f1817dde7e91b9623f5ca6093566795dfecb9575b5d7b44dc5e22a7d49d1404dec2912e170dd8cfe73f57f43d758a17f70778b2a593c3c3625cb499ac8250ad3923669f9e1110ee6204b0bed2db8bdb3b6e61fdae2

    If you can go from:

    A → B
    B → C

    Then you must allow:

    A → C

    This arrow represents doing both steps in sequence.

    In Kotlin, this is just function composition:

    fun <A, B, C> compose(
        f: (A) -> B,
        g: (B) -> C
    ): (A) -> C = { a -> g(f(a)) }

    A Kotlin story (very real)

    fun parse(input: String): Int = input.length
    fun validate(n: Int): Boolean = n > 3
    fun render(ok: Boolean): String =
        if (ok) "Valid" else "Invalid"

    You didn’t plan a pipeline upfront — but Kotlin allows this:

    val pipeline =
        compose(
            compose(::parse, ::validate),
            ::render
        )

    That pipeline emerged.

    This is exactly what category theory calls a free category.

    What “Free Category” Actually Means

    A free category is just a way of not forgetting anything. Imagine a map with places and roads. Every place becomes an object, every road becomes a connection, and every possible route you can travel is remembered. Staying where you are also counts as a route — that’s the identity. If you can go from A to B and then from B to C, the system simply accepts that A to C is a valid path too. Nothing clever is happening; it’s just acknowledging what’s already possible.

    What makes it “free” is that no extra rules are added on top. No shortcuts are assumed, no paths are merged, and no optimizations are made. If there are ten different ways to reach the same destination, all ten are kept. A free category doesn’t try to decide which path is better or faster — it only records the structure of how things can be connected. It’s the most honest starting point: everything that can be composed exists, and nothing more is assumed.

    #MathForDevelopers#FunctionalProgramming#Kotlin#SoftwareEngineering#BuildInPublic#CategoryTheory#FreeCategory#NothingType#TypeSystems#FPFoundations#ProgrammingConcepts#LearningInPublic